package com.mingqijia.gassafety.webserver.service.impl;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Date;
import java.util.Calendar;
import java.util.Comparator;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.annotation.PostConstruct;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.UtilException;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.system.SystemUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gap.basic.base.CommonResponse;
import com.gap.basic.exception.BizException;
import com.gap.filestorage.config.TencentFileStorageConfiguration;
import com.github.pagehelper.util.StringUtil;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.mingqijia.gassafety.authority.api.resp.config.DictionaryItemRespDTO;
import com.mingqijia.gassafety.authority.dal.helper.ConfigureHolder;
import com.mingqijia.gassafety.db.entity.vo.StateCountVo;
import com.mingqijia.gassafety.db.influxdb.config.InfluxDBConfiguration;
import com.mingqijia.gassafety.db.influxdb.config.InfluxDBConnect;
import com.mingqijia.gassafety.shared.constant.runningReport.ReportAlarmTypeEnum;
import com.mingqijia.gassafety.shared.constant.runningReport.ReportContentTypeEnum;
import com.mingqijia.gassafety.shared.dto.LogVO;
import com.mingqijia.gassafety.shared.dto.RunningReportOnOffDTO;
import com.mingqijia.gassafety.shared.dto.cms.CmsInfoResDTO;
import com.mingqijia.gassafety.shared.dto.user.PhoneUserDTO;
import com.mingqijia.gassafety.shared.utils.IOUtil;
import com.mingqijia.gassafety.shared.utils.TimeUtil;
import com.mingqijia.gassafety.shared.utils.ZipUtil;
import com.mingqijia.gassafety.shared.utils.commonUtils.*;
import com.mingqijia.gassafety.shared.utils.message.AppletMessageService;
import com.mingqijia.gassafety.shared.utils.message.CmsMessageService;
import com.mingqijia.gassafety.shared.utils.user.UserRemoteService;
import com.mingqijia.gassafety.webserver.dto.RunningReportAlarmDetailDTO;
import com.mingqijia.gassafety.webserver.feign.ConsoleSkFeignClient;
import com.mingqijia.gassafety.webserver.request.runningReport.RunningReportEditPreviewRequest;
import com.mingqijia.gassafety.webserver.response.runningReport.RunningReportDeviceListResponse;
import com.mingqijia.gassafety.webserver.response.runningReport.RunningReportPreviewResponse;
import com.mingqijia.gassafety.webserver.response.sk.ConsoleSkUserData;
import com.mingqijia.gassafety.webserver.response.sk.ConsoleSkUserListData;
import com.mingqijia.gassafety.webserver.response.sk.ConsoleSkUserListResponse;
import com.mingqijia.gassafety.webserver.service.BusinessNoticeService;
import com.mingqijia.gassafety.webserver.utils.LogRecordAspect;
import org.apache.commons.collections.CollectionUtils;
import com.gap.filestorage.service.FileStorage;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.mingqijia.gassafety.db.entity.*;

import com.mingqijia.gassafety.db.mapper.*;
import com.mingqijia.gassafety.shared.common.ContextHolder;
import com.mingqijia.gassafety.shared.constant.*;
import com.mingqijia.gassafety.shared.enums.YesNoEnum;
import com.mingqijia.gassafety.shared.utils.ApplicationUtils;
import com.mingqijia.gassafety.webserver.dto.RunningReportAlarmSummaryDTO;
import com.mingqijia.gassafety.webserver.request.RunningReportRequest;
import com.mingqijia.gassafety.webserver.response.*;
import com.mingqijia.gassafety.webserver.service.RunningReportDataService;
import com.mingqijia.gassafety.webserver.service.RunningReportConfigService;
import com.mingqijia.gassafety.webserver.service.RunningReportService;
import com.mingqijia.gassafety.webserver.service.FileExportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.influxdb.dto.QueryResult;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import static com.mingqijia.gassafety.shared.constant.Constants.IS_DELETED_FALSE;
import static com.mingqijia.gassafety.webserver.constant.DeviceConstant.IS_DELETED_0;

/**
 * <p>
 * 运行报告管理 服务实现类
 * </p>
 *
 * @author mby
 * @since 2024-03-11
 */
@Service
@Slf4j
public class RunningReportServiceImpl extends ServiceImpl<RunningReportMapper, RunningReport> implements RunningReportService {

    @Autowired
    ConfigureHolder holder;

    @Value( "${gassafety.echart.path}" )
    private String echartPath;

    @Value( "${gassafety.h5.common.path}" )
    private String h5CommonPath;

    @Autowired
    DtuMapper dtuMapper;
    @Autowired
    ConsumerMapper consumerMapper;
    @Autowired
    HistoryAlarmMapper historyAlarmMapper;
    @Autowired
    HistoryBrokenMapper historyBrokenMapper;
    @Autowired
    RunningReportConfigMapper runningReportConfigMapper;
    @Autowired
    RunningReportMapper runningReportMapper;
    @Autowired
    RunningReportDataMapper runningReportDataMapper;
    @Autowired
    RunningReportAuditConfigMapper runningReportAuditConfigMapper;

    @Autowired
    FileExportService fileExportService;
    @Autowired
    RunningReportConfigService runningReportConfigService;
    @Autowired
    RunningReportDataService runningReportDataService;
    @Autowired
    BusinessNoticeService noticeService;

    @Autowired
    FileStorage fileStorage;

    @Autowired
    ConsoleSkFeignClient consoleSkFeignClient;

    @Autowired
    CmsMessageService cmsMessageService;

    @Autowired
    AppletMessageService appletMessageService;

    @Autowired
    UserRemoteService userRemoteService;

    @Autowired
    InfluxDBConfiguration influxDBConfiguration;

    /** 是否初始化了 */
    private static boolean initFlag = false;

    private ExecutorService executor = Executors.newFixedThreadPool(10);
    private static String tipsPic1 = "";

    private static String tipsPic2 = "";

    private static String tipsPic3 = "";
    private static final String phantomPath = "/phantomjs";
    private static final String JSpath = "/echarts-convert.js";

    /**
     * 临时目录-代码文件夹
     **/
    private static  String FILE_STORAGE_PATH = "" ;

    /**
     * 临时目录-zip压缩包
     **/
    private static  String FILE_ZIP_PATH = "";

    /**
     * 临时目录-数据源txt
     **/
    private static  String FILE_DATA_TXT_PATH = "";

    /**
     * 临时目录-echart相关文件
     **/
    private static  String FILE_ECHART_PATH = "";

    /**
     * 临时目录-echart图
     **/
    private static  String FILE_ECHART_IMG_PATH = "";

    /**
     * 临时目录-pdf用字体文件
     **/
    private static  String FILE_FONT_PATH = "";

    /** jar包中字体的位置 */
    private static final String ECHARTS = "echart";

    /** jar包中字体的位置 */
    private static final String FONTS = "fonts";

//    /**
//     * 字体基础设置
//     **/
//    private static  BaseFont baseFont;

    private static float paddingTop = 5f; // 例如设置为 5 个点的上边距
    private static float paddingBottom = 5f; // 例如设置为 5 个点的下边距

    @PostConstruct
    public void initPath() {
        tipsPic1 = echartPath + "echart/png1.png";
        tipsPic2 = echartPath + "echart/png2.png";
        tipsPic3 = echartPath + "echart/png3.png";
        FILE_STORAGE_PATH = echartPath + "temp/export/" ;
        FILE_ZIP_PATH = echartPath +  "temp/zip/";
        FILE_DATA_TXT_PATH = echartPath +  "/temp/txt/";
        FILE_ECHART_PATH = echartPath +  "echart";
        FILE_FONT_PATH = echartPath +  "fonts";
        FILE_ECHART_IMG_PATH = echartPath +  "temp/img/";
    }

    @Override
    public List<StateCountResponse> runningReportTab(RunningReportRequest request) {
        String spId = ApplicationUtils.getWorkingSpId();
        if (!StringUtils.isEmpty(request.getSpId())) {
            spId = request.getSpId();
        }
        Map<String, Object> param = new HashMap<>();
        param.put("reportDate", request.getReportDate());
        param.put("spId", spId);
        if (request.getAlarmHandleStatus() != null) {
            param.put("alarmHandleStatus", request.getAlarmHandleStatus());
        }
        if (CollectionUtils.isNotEmpty(request.getCheckStatus())) {
            param.put("checkStatus", request.getCheckStatus());
        }
        if (StringUtils.isNotEmpty(request.getCustType())) {
            param.put("custType", request.getCustType());
        }
        if (CollectionUtils.isNotEmpty(request.getDeviceType())) {
            param.put("deviceType", request.getDeviceType());
        }
        if (StringUtils.isNotEmpty(request.getSubsCode())) {
            param.put("subsCode", request.getSubsCode());
        }
        if (StringUtils.isNotEmpty(request.getCustName())) {
            param.put("custName", request.getCustName());
        }
        if (StringUtils.isNotEmpty(request.getCustAddress())) {
            param.put("custAddress", request.getCustAddress());
        }
        if (StringUtils.isNotEmpty(request.getPhone())) {
            param.put("phone", request.getPhone());
        }
        if (StringUtils.isNotEmpty(request.getImei())) {
            param.put("imei", request.getImei());
        }
        if (StringUtils.isNotEmpty(request.getCustPhone())) {
            param.put("custPhone", request.getCustPhone());
        }
        if (StringUtils.isNotEmpty(request.getCommunicationMode())) {
            param.put("communicationMode", request.getCommunicationMode());
        }
        Map<String, BigDecimal> stateMap = runningReportMapper.countState(param);
        log.info("runningReportTab-stateMap:{}", JSONObject.toJSONString(stateMap));
        if (stateMap == null) {
            stateMap = new HashMap<>(); //一条数据都没有的时候会为空
        }
        List<StateCountResponse> response = new ArrayList<>();
        response.add(new StateCountResponse(ReportContentTypeEnum.OFFLINE.getCode(), ReportContentTypeEnum.OFFLINE.getMsg(), stateMap.get("count_3") == null ? 0 : stateMap.get("count_3").intValue()));
        response.add(new StateCountResponse(ReportContentTypeEnum.NO_ALARM.getCode(), ReportContentTypeEnum.NO_ALARM.getMsg(), stateMap.get("count_1") == null ? 0 : stateMap.get("count_1").intValue()));
        response.add(new StateCountResponse(ReportContentTypeEnum.ALARM.getCode(), ReportContentTypeEnum.ALARM.getMsg(), stateMap.get("count_0") == null ? 0 : stateMap.get("count_0").intValue()));
        response.add(new StateCountResponse(ReportContentTypeEnum.BROKEN.getCode(), ReportContentTypeEnum.BROKEN.getMsg(), stateMap.get("count_2") == null ? 0 : stateMap.get("count_2").intValue()));
        return response;
    }

    @Override
    public Integer canGenerate(String reportDate) {
        String spId = ApplicationUtils.getWorkingSpId();
        QueryWrapper<RunningReport> allQueryWrapper = new QueryWrapper<>();
        allQueryWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                .eq(RunningReport::getIsDeleted, YesNoEnum.N.getCode())
                .eq(RunningReport::getSpId, spId);
        Integer allNumber = runningReportMapper.selectCount(allQueryWrapper);
        QueryWrapper<RunningReport> unCheckQueryWrapper = new QueryWrapper<>();
        unCheckQueryWrapper.lambda().eq(RunningReport::getCheckStatus, 0)
                .eq(RunningReport::getReportDate, reportDate)
                .eq(RunningReport::getIsDeleted, YesNoEnum.N.getCode())
                .eq(RunningReport::getSpId, spId);
        Integer checkNumber = runningReportMapper.selectCount(unCheckQueryWrapper);
        if (checkNumber > 0 && allNumber == checkNumber ) {
            return 0;
        } else {
            return 1;
        }
    }

    @Override
    public Integer canDownload(String reportDate) {
        String spId = ApplicationUtils.getWorkingSpId();
        QueryWrapper<RunningReport> allQueryWrapper = new QueryWrapper<>();
        allQueryWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                .eq(RunningReport::getIsDeleted, YesNoEnum.N.getCode())
                .eq(RunningReport::getSpId, spId);
        Integer allNumber = runningReportMapper.selectCount(allQueryWrapper);
        QueryWrapper<RunningReport> updateQueryWrapper = new QueryWrapper<>();
        updateQueryWrapper.lambda().ne(RunningReport::getUpdateStatus, 1)
                .eq(RunningReport::getReportDate, reportDate)
                .eq(RunningReport::getIsDeleted, YesNoEnum.N.getCode())
                .eq(RunningReport::getSpId, spId);
        Integer updateNumber = runningReportMapper.selectCount(updateQueryWrapper);
        if (updateNumber > 0 && allNumber == updateNumber ) {
            return 0;
        } else {
            return 1;
        }
    }

    @Override
    public PageUtil<RunningReportResponse> runningReportList(RunningReportRequest request) {
        String spId = ApplicationUtils.getWorkingSpId();
        if (!StringUtils.isEmpty(request.getSpId())) {
            spId = request.getSpId();
        }

        List<Integer> consumerTypeList = new ArrayList<>();
        if (StringUtils.isNotEmpty(request.getCustType())) {
            consumerTypeList = consumerMapper.getCustomerIdListByType(spId, request.getCustType());
            log.info("consumerTypeList:{}", consumerTypeList);
            if (CollectionUtils.isEmpty(consumerTypeList)) {
                return new PageUtil<>();
            }

        }
        Page<ConsumerServiceInfo> page = null;
        QueryWrapper<RunningReport> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(RunningReport::getSpId, spId)
            .eq(RunningReport::getIsDeleted, IS_DELETED_0)
            .eq(StringUtils.isNotEmpty(request.getReportDate()),RunningReport::getReportDate, request.getReportDate())
            .like(request.getReportContentType() != null, RunningReport::getReportContentType, request.getReportContentType())
            .in(CollectionUtils.isNotEmpty(request.getCheckStatus()), RunningReport::getCheckStatus, request.getCheckStatus())
            .in(CollectionUtils.isNotEmpty(consumerTypeList), RunningReport::getConsumerId, consumerTypeList);

        if (request.getAlarmHandleStatus() != null) {
            if (request.getAlarmHandleStatus() == 0) {
                //0-报警已处理
                queryWrapper.lambda().gt(RunningReport::getAlarmProcessed, 0)
                    .eq(RunningReport::getAlarmProcessing, 0)
                    .eq(RunningReport::getAlarmPending, 0);
            }
            if (request.getAlarmHandleStatus() == 1) {
                //0-存在报警未处理
                queryWrapper.lambda().and(lqw2 -> {
                    lqw2.gt(RunningReport::getAlarmProcessing, 0)
                        .or().gt(RunningReport::getAlarmPending, 0);
                });
            }
            if (request.getAlarmHandleStatus() == 2) {
                //0-故障已处理
                queryWrapper.lambda().gt(RunningReport::getBrokenProcessed, 0)
                    .eq(RunningReport::getBrokenProcessing, 0)
                    .eq(RunningReport::getBrokenPending, 0);
            }
            if (request.getAlarmHandleStatus() == 3) {
                //0-存在故障未处理
                queryWrapper.lambda().and(lqw2 -> {
                    lqw2.gt(RunningReport::getBrokenProcessing, 0)
                        .or().gt(RunningReport::getBrokenPending, 0);
                });
            }
        }

        if (CollectionUtils.isNotEmpty(request.getDeviceType())) {
            queryWrapper.lambda().and(lqw2 -> {
                lqw2.like(RunningReport::getDeviceType, request.getDeviceType().get(0));
                if (request.getDeviceType().size() >= 2) {
                    lqw2.or().like(request.getDeviceType().size() >= 2, RunningReport::getDeviceType, request.getDeviceType().get(1));
                }
                if (request.getDeviceType().size() >= 3) {
                    lqw2.or().like(request.getDeviceType().size() >= 3, RunningReport::getDeviceType, request.getDeviceType().get(2));
                }
            });
        }
        if (StringUtil.isNotEmpty(request.getImei())) {
            QueryWrapper<Dtu> dtuQueryWrapper = new QueryWrapper<>();
            dtuQueryWrapper.lambda().eq(Dtu::getIMEI, request.getImei())
                    .eq(Dtu::getIsDeleted, IS_DELETED_FALSE)
                    .eq(Dtu::getSpId, spId);
            Dtu dtu = dtuMapper.selectOne(dtuQueryWrapper);
            if (dtu != null) {
                queryWrapper.lambda().eq(RunningReport::getConsumerId, dtu.getConsumerId());
            } else {
                queryWrapper.lambda().eq(RunningReport::getConsumerId, null);
            }
        }
        if (StringUtil.isNotEmpty(request.getCommunicationMode())) {
            QueryWrapper<Dtu> dtuQueryWrapper = new QueryWrapper<>();
            dtuQueryWrapper.lambda().eq(Dtu::getCommunicationMode, request.getCommunicationMode())
                    .ne(Dtu::getConsumerId, 0)
                    .isNotNull(Dtu::getConsumerId)
                    .eq(Dtu::getIsDeleted, IS_DELETED_FALSE)
                    .eq(Dtu::getSpId, spId);
            List<Dtu> dtus = dtuMapper.selectList(dtuQueryWrapper);
            List<Integer> consumerIds = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(dtus)) consumerIds = dtus.stream().map(Dtu::getConsumerId).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(consumerIds)) {
                queryWrapper.lambda().in(RunningReport::getConsumerId, consumerIds);
            } else {
                queryWrapper.lambda().eq(RunningReport::getConsumerId, null);
            }
        }
        if (StringUtil.isNotEmpty(request.getSubsCode()) || StringUtil.isNotEmpty(request.getCustName()) || StringUtil.isNotEmpty(request.getCustAddress()) ||
                StringUtil.isNotEmpty(request.getCustPhone())) {
            QueryWrapper<Consumer> consumerQueryWrapper = new QueryWrapper<>();
            consumerQueryWrapper.lambda().eq(StringUtil.isNotEmpty(request.getSubsCode()), Consumer::getSubsCode, request.getSubsCode())
                    .like(StringUtil.isNotEmpty(request.getCustName()), Consumer::getCustName, request.getCustName())
                    .like(StringUtil.isNotEmpty(request.getCustAddress()), Consumer::getCustAddress, request.getCustAddress())
                    .like(StringUtil.isNotEmpty(request.getCustPhone()), Consumer::getCustPhone, request.getCustPhone())
                    .eq(Consumer::getIsDeleted, IS_DELETED_FALSE)
                    .eq(Consumer::getSpId, spId);
            List<Consumer> consumers = consumerMapper.selectList(consumerQueryWrapper);
            if (CollectionUtils.isNotEmpty(consumers)) {
                List<Integer> consumerIds = consumers.stream().map(Consumer::getId).collect(Collectors.toList());
                queryWrapper.lambda().in(RunningReport::getConsumerId, consumerIds);
            }else {
                queryWrapper.lambda().eq(RunningReport::getConsumerId, null);
            }
        }
        queryWrapper.lambda().orderByAsc(RunningReport::getCheckStatus);
        queryWrapper.lambda().orderByDesc(RunningReport::getUpdatedAt, RunningReport::getCreatedAt);
        page = PageHelper.startPage(request.getPage(), request.getPageSize());
        List<RunningReport> runningReportList = this.list(queryWrapper);
        List<RunningReportResponse> list = BeanConvertUtils.convertListTo(runningReportList, RunningReportResponse::new);
        // 客户列表
        List<Integer> consumerIdList = list.stream()
            .map(RunningReportResponse::getConsumerId).distinct().collect(Collectors.toList());
        if (consumerIdList.size() > 0) {
            // 查询客户信息
            QueryWrapper<Consumer> consumerQueryWrapper = new QueryWrapper<>();

            consumerQueryWrapper.lambda().in(Consumer::getId, consumerIdList)
                .eq(Consumer::getSpId, spId)
                .eq(Consumer::getIsDeleted, IS_DELETED_0);
            List<Consumer> consumerList = consumerMapper.selectList(consumerQueryWrapper);
            Map<Integer, Consumer> consumerMap = consumerList.stream().collect(Collectors.toMap(Consumer::getId, Function.identity()));
            for(RunningReportResponse response : list) {
                if (consumerMap.get(response.getConsumerId()) != null) {
                    response.setSubsCode(consumerMap.get(response.getConsumerId()).getSubsCode());
                    response.setCustName(consumerMap.get(response.getConsumerId()).getCustName());
                    response.setCustType(consumerMap.get(response.getConsumerId()).getCustType());
                    if (StringUtils.isEmpty(response.getCustType()) && StringUtils.isNotEmpty(response.getSubsCode())) {
                        response.setCustType("未知");
                    }
                    if (StringUtils.isEmpty(response.getCustType()) && StringUtils.isEmpty(response.getSubsCode())) {
                        response.setCustType("其他");
                    }
                }
                // 设备类型
                if (StringUtils.isNotEmpty(response.getDeviceType())) {
                    String[] types = response.getDeviceType().split(Constants.STR_COMMA);
                    StringBuilder builder = new StringBuilder();
                    for (String type : types) {
                        builder.append(EquipmentType.parse(type).getName()).append(Constants.STR_COMMA);
                    }
                    response.setDeviceType(builder.length() > 0 ? builder.deleteCharAt(builder.length() - 1).toString() : Constants.BLANK);
                }
                // 离线时长
                response.setOfflineTimeStr(TimeUtil.secondToStr(response.getOfflineTime()));
                // 报告内容
                if (StringUtils.isNotBlank(response.getReportContentType())) {
                    StringBuffer sb = new StringBuffer(Constants.BLANK);
                    String[] arr = response.getReportContentType().split(Constants.STR_COMMA);
                    for (String contentType: arr) {
                        if (StringUtils.isNotBlank(contentType) && NumberUtils.isNumber(contentType)) {
                            sb.append(ReportContentTypeEnum.getNameByCode(Integer.parseInt(contentType))).append(Constants.STR_COMMA);
                        }
                    }
                    if (sb.length() > 0) {
                        response.setReportContentTypeName(sb.deleteCharAt(sb.length() - 1).toString());

                    }
                }
                // 报告审核状态
                response.setCheckStatusName((response.getCheckStatus() == null || response.getCheckStatus() == 0) ? "待审核" : (response.getCheckStatus() == 1 ? "已审核" : "无需审核"));
                // 报告更新状态
                response.setUpdateStatusName((response.getUpdateStatus() == null || response.getUpdateStatus() == 0) ? Constants.BLANK : (response.getUpdateStatus() == 1 ? "更新中" : "已更新"));
            }
        }

        PageUtil<RunningReportResponse> pageUtil = new PageUtil<>();
        pageUtil.setPage(request.getPage());
        pageUtil.setPageSize(request.getPageSize());
        pageUtil.setTotal(page.getTotal());
        pageUtil.setList(list);
        return pageUtil;
    }

    @Override
    public List<String> getCustTypeList() {
        String spId = ApplicationUtils.getWorkingSpId();
        List<String> custTypes = consumerMapper.selectUserType(spId);
        if (CollectionUtils.isNotEmpty(custTypes)) {
            custTypes.remove("");
            // 其他
            if (consumerMapper.selectUserTypeCount(spId, "其他") > 0) {
                custTypes.add("其他");
            }
            // 未知
            if (consumerMapper.selectUserTypeCount(spId, "未知") > 0) {
                custTypes.add("未知");
            }
        }

        return custTypes;
    }

    @Override
    public RunningReportDetailResponse detail(Integer id) {
        // 查询运行报告
        RunningReport report = this.getById(id);
        if (ObjectUtils.isEmpty(report)) {
            throw new BizException("运行报告不存在");
        }
        StringBuilder dateString = new StringBuilder();
        Calendar c = Calendar.getInstance();
        c.setTime(DateUtils.toDate(report.getReportDate(), "yyyy-MM"));
        dateString.append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月");
        String time = new StringBuilder().append(c.get(Calendar.MONTH) + 1).append("月").toString();
        // 查询运行报告配置和模版
        RunningReportConfig config = runningReportConfigService.getById(report.getConfigId());
        if (ObjectUtils.isEmpty(config)) {
            throw new BizException("运行报告配置和模版信息不存在");
        }
        // 查询客户
        Consumer consumer = consumerMapper.selectById(report.getConsumerId());
        if (ObjectUtils.isEmpty(consumer)) {
            throw new BizException("客户不存在");
        }
        RunningReportDetailResponse response = new RunningReportDetailResponse();
        BeanUtil.copyProperties(config, response);
        response.setMonth(c.get(Calendar.MONTH) + 1);
        response.setReportContentType(report.getReportContentType());
        response.setConsumerId(consumer.getId());
        response.setSubsCode(consumer.getSubsCode());
        response.setCustName(consumer.getCustName());
        response.setCustAddress(consumer.getCustAddress());
        if (!report.getReportContentType().equals(ReportContentTypeEnum.NO_ALARM.getCode().toString())) {
            // 存在异常
            if (response.getIsAlarmSummary() == ShowAndSelectEnum.SHOW.getCode()) {
                response.setAlarmSummaryContent(response.getAlarmSummaryContent()
                    .replace("#subsName#", StringUtils.isEmpty(consumer.getCustName()) ? "" : consumer.getCustName())
                    .replace("#Date#", dateString.toString()));
                response.setAlarmSummaryTitle(response.getAlarmSummaryTitle()
                    .replace("#subsName#", StringUtils.isEmpty(consumer.getCustName()) ? "" : consumer.getCustName())
                    .replace("#Date#", dateString.toString()));
                //报警总结列表
                if (StringUtils.isNotEmpty(config.getAlarmSummaryListShow())) {
                    List<FieldListShowResponse> alarmSummaryList = JSON.parseArray(config.getAlarmSummaryListShow(), FieldListShowResponse.class);
                    List<PageColumns> alarmSummaryColumns = alarmSummaryList.stream()
                        .filter(entity -> entity.getShowStatus() != null && entity.getShowStatus() == 0 )
                        .map(entity -> new PageColumns(entity.getFieldName(), entity.getFieldCode()))
                        .collect(Collectors.toList()); // 返回一个新的已排序的列表
                    response.setAlarmSummaryColumns(alarmSummaryColumns);
                }
                List<RunningReportData> runningReportDataList = runningReportDataMapper.queryAlarmSummaryList(id);
                response.setAlarmSummaryDataTotal(0);
                Map<String, List<RunningReportData>> runningReportDataMap = new HashMap<>();
                if (CollectionUtils.isNotEmpty(runningReportDataList)) {
                    runningReportDataList.stream().forEach(data -> {
                        String key = new StringBuilder().append(data.getAlarmType()).append(Constants.UNDERLINE).append(data.getValveBrokenInfo().replace("正常",Constants.BLANK).replace(";",Constants.BLANK)).toString();
                        if (runningReportDataMap.get(key) == null) {
                            runningReportDataMap.put(key, new ArrayList<>());
                        }
                        response.setAlarmSummaryDataTotal(response.getAlarmSummaryDataTotal() + data.getNumber());
                        runningReportDataMap.get(key).add(data);
                    });
                }
                List<RunningReportAlarmSummaryDTO> alarmSummaryList = new ArrayList<>();
                if (runningReportDataMap.size() > 0) {

                    runningReportDataMap.forEach((key, value) -> {
                        RunningReportAlarmSummaryDTO dto = new RunningReportAlarmSummaryDTO();
                        dto.setTime(time);
                        dto.setAlarmType(ReportAlarmTypeEnum.getNameByCode(value.get(0).getAlarmType()));
                        dto.setValveBrokenInfo(value.get(0).getValveBrokenInfo());
                        if (StringUtils.isBlank(dto.getValveBrokenInfo())) {
                            dto.setValveBrokenInfo(Constants.STR_STRIKETHROUGH);
                        }
                        dto.setAlarmNumber(0);
                        dto.setPendingNumber(0);
                        dto.setProcessingNumber(0);
                        dto.setProcessedNumber(0);
                        for (RunningReportData data : value) {
                            if (data.getAppealStatus() == 0) {
                                dto.setPendingNumber(dto.getPendingNumber() + data.getNumber());
                            } else if (data.getAppealStatus() == 1) {
                                dto.setProcessingNumber(dto.getProcessingNumber() + data.getNumber());
                            } else {
                                dto.setProcessedNumber(dto.getProcessedNumber() + data.getNumber());
                            }
                            dto.setAlarmNumber(dto.getAlarmNumber() + data.getNumber());
                        }
                        dto.setProportion(new StringBuilder().append(BigDecimal.valueOf((double) (dto.getAlarmNumber() * 100)/ response.getAlarmSummaryDataTotal()).setScale(2, RoundingMode.HALF_UP)).append(Constants.PERCENT).toString());
                        if (StringUtils.isBlank(dto.getProportion())) {
                            dto.setProportion(Constants.STR_STRIKETHROUGH);
                        }
                        if (value.get(0).getAlarmType() - ReportAlarmTypeEnum.OFFLINE.getCode() != 0) {
                            StringBuilder builder = new StringBuilder();
                            if (dto.getPendingNumber() != null && dto.getPendingNumber() > 0) {
                                builder.append("待处理（").append(dto.getPendingNumber()).append("）\n");
                            }
                            if (dto.getProcessingNumber() != null && dto.getProcessingNumber() > 0) {
                                builder.append("处理中（").append(dto.getProcessingNumber()).append("）\n");
                            }
                            if (dto.getProcessedNumber() != null && dto.getProcessedNumber() > 0) {
                                builder.append("已处理（").append(dto.getProcessedNumber()).append("）\n");
                            }
                            dto.setAppealStatus(builder.length() > 0 ? builder.deleteCharAt(builder.length() - 1).toString() : Constants.BLANK);

                        } else {
                            dto.setAppealStatus(Constants.STR_STRIKETHROUGH);
                        }
                        alarmSummaryList.add(dto);
                    });
                }
                response.setAlarmSummaryDatas(alarmSummaryList);
                // 报警类别分析图示
                if (response.getCategoryAnalysisShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    response.setAlarmTotal(report.getAlarmPending() + report.getAlarmProcessing() + report.getAlarmProcessed());
                    response.setBrokenTotal(report.getBrokenPending() + report.getBrokenProcessing() + report.getBrokenProcessed());
                    response.setOfflineTotal(report.getOfflineTotal());
                }
                // 报警情况分析图示
                if (response.getSituationAnalysisShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    Map<String, Integer> situationAnalysisMap = new HashMap<>();
                    List<RunningReportData> list = runningReportDataMapper.queryDataGroupByTypeAndReason(report.getId());
                    if (CollectionUtils.isNotEmpty(list)) {
                        list.forEach(x -> {
                            situationAnalysisMap.put(new StringBuilder().append(ReportAlarmTypeEnum.getNameByCode(x.getAlarmType()))
                                .append(Constants.LEFT_BRACKET).append(x.getValveBrokenInfo()).append(Constants.RIGHT_BRACKET).toString(), x.getNumber());
                        });
                    }
                    response.setSituationAnalysisMap(situationAnalysisMap);
                }
            }
            if (response.getIsAlarmDetail() == ShowAndSelectEnum.SHOW.getCode()) {
                response.setAlarmDetailTitle(response.getAlarmDetailTitle()
                        .replace("#subsName#", StringUtils.isEmpty(consumer.getCustName()) ? "" : consumer.getCustName())
                        .replace("#Date#", dateString.toString()));
                //报警明细列表
                if (StringUtils.isNotEmpty(config.getAlarmDetailListShow())) {
                    List<FieldListShowResponse> alarmDetailList = JSON.parseArray(config.getAlarmDetailListShow(), FieldListShowResponse.class);
                    List<PageColumns> alarmDetailColumns = alarmDetailList.stream()
                        .filter(entity -> entity.getShowStatus() != null && entity.getShowStatus() == 0 )
                        .map(entity -> new PageColumns(entity.getFieldName(), entity.getFieldCode()))
                        .collect(Collectors.toList()); // 返回一个新的已排序的列表
                    response.setAlarmDetailColumns(alarmDetailColumns);
                    QueryWrapper<RunningReportData> runningReportDataQueryWrapper = new QueryWrapper<>();
                    runningReportDataQueryWrapper.lambda().eq(RunningReportData::getReportId, report.getId())
                        .eq(RunningReportData::getIsDeleted, 0);
                    List<RunningReportData> runningReportDataList = runningReportDataMapper.selectList(runningReportDataQueryWrapper);

                    Integer number = 1;
                    List<RunningReportAlarmDetailDTO> alarmDetailDataList = new ArrayList<>();
                    for (RunningReportData x : runningReportDataList) {
                        RunningReportAlarmDetailDTO dto = new RunningReportAlarmDetailDTO();
                        dto.setNumber(number);
                        dto.setImei(x.getImei());
                        dto.setAlarmAddress(x.getAlarmAddress());
                        if (StringUtils.isBlank(dto.getAlarmAddress())) {
                            dto.setAlarmAddress(Constants.STR_STRIKETHROUGH);
                        }
                        dto.setAlarmType(ReportAlarmTypeEnum.getNameByCode(x.getAlarmType()));
                        dto.setAlarmTime(DateUtils.format(x.getAlarmTime(), "yyyy-MM-dd HH:mm:ss"));
                        if (x.getOfflineExtend() == 1) {
                            // 跨月持续离线
                            dto.setAlarmTime(new StringBuffer("从").append(dto.getAlarmTime()).append("持续离线").toString());
                        }
                        if (StringUtils.isBlank(dto.getAlarmTime())) {
                            dto.setAlarmTime(Constants.STR_STRIKETHROUGH);
                        }

                        if (x.getAlarmType() - ReportAlarmTypeEnum.ALARM.getCode() == 0) {
                            dto.setConcentration(x.getConcentration() + Constants.CONCENTRATION);
                        } else if (x.getAlarmType() - ReportAlarmTypeEnum.OFFLINE.getCode() == 0) {
                            dto.setConcentration("离线" + TimeUtil.secondToStr(x.getOfflineTime()));
                        }
                        if (StringUtils.isBlank(dto.getConcentration())) {
                            dto.setConcentration(Constants.STR_STRIKETHROUGH);
                        }
                        dto.setAppealTime(DateUtils.format(x.getAppealTime(), "yyyy-MM-dd HH:mm:ss"));
                        if (StringUtils.isBlank(dto.getAppealTime())) {
                            dto.setAppealTime(Constants.STR_STRIKETHROUGH);
                        }

                        if (x.getAlarmType() - ReportAlarmTypeEnum.OFFLINE.getCode() == 0) {
                            dto.setAppealStatus(Constants.STR_STRIKETHROUGH);
                        } else {
                            dto.setAppealStatus(x.getAppealStatus() == 0 ? "待处理" : x.getAppealStatus() == 1 ? "处理中" : "已处理");
                        }
                        dto.setValveBrokenInfo(x.getValveBrokenInfo());
                        if (StringUtils.isBlank(dto.getValveBrokenInfo())) {
                            dto.setValveBrokenInfo(Constants.STR_STRIKETHROUGH);
                        }

                        alarmDetailDataList.add(dto);
                        number ++;
                    }
                    response.setAlarmDetailDatas(alarmDetailDataList);
                }
            }
            if (response.getIsTips() == ShowAndSelectEnum.SHOW.getCode()) {
                response.setTipsContent(response.getTipsContent()
                    .replace("#subsName#", StringUtils.isEmpty(consumer.getCustName()) ? "" : consumer.getCustName())
                    .replace("#Date#", dateString.toString()));
            }
        } else {
            // 无报警,无异常，正常运行
            response.setNoAlarmContent(response.getNoAlarmContent()
                .replace("#subsName#", StringUtils.isEmpty(consumer.getCustName()) ? "" : consumer.getCustName())
                .replace("#Date#", dateString.toString()));
        }

        return response;
    }

    /**
     * 重新生产报告数据
     * @param id 运行报告
     * @param updateConfig  true更新配置 false不更新配置只更新数据
     */
    public void updateReportData(Integer id, Boolean updateConfig) {
        log.info("数据更新中,id:{},updateConfig:{}", id, updateConfig);
        RunningReport report = this.getById(id);
        if (ObjectUtils.isEmpty(report)) {
            log.info("运行报告不存在,id:{}", id);
        }
        // 报警原因字典
        log.info("数据更新中,获取字典");
        Map<String, String> reasonMap = new HashMap<>();
        try {
            List<DictionaryItemRespDTO> alarmReasonDict = holder.getDictionaryByKeyNoCache(
                    Constants.ALARM_REASON, report.getSpId());
            reasonMap = alarmReasonDict.stream().collect(Collectors.toMap(DictionaryItemRespDTO::getValue, DictionaryItemRespDTO::getName));
        } catch(Exception e) {
            log.info("getAlarmList-alarmReasonDict-error:{}", e.getMessage());
        }
        Map<String, String> alarmReasonMap = reasonMap;
        log.info("数据更新中,获取字典：{}", alarmReasonMap);
        Date startDate = DateUtils.toDate(report.getReportDate(), "yyyy-MM");
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        Integer monthDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
        c.add(Calendar.MONTH, 1);
        Date endDate = DateUtils.toDate(DateUtils.dateFormat(c.getTime(), "yyyy-MM"), "yyyy-MM");
        Long startSecond = startDate.getTime() / 1000; // 该月开始毫秒数
        Long endSecond = endDate.getTime() / 1000;// 该月结束-下月开始毫秒数
        Consumer consumer = consumerMapper.selectById(report.getConsumerId());
        if (ObjectUtils.isEmpty(consumer)) {
            log.info("客户不存在,id:{}", report.getConsumerId());
        }
        log.info("数据更新中,consumer:{}", consumer.toString());
        // 将原来的数据全部删除
        UpdateWrapper<RunningReportData> deleteWrapper = new UpdateWrapper<>();
        deleteWrapper.lambda().eq(RunningReportData::getReportId, id)
            .eq(RunningReportData::getIsDeleted, Constants.IS_DELETED_FALSE);
        RunningReportData updateData = new RunningReportData();
        updateData.setIsDeleted(YesNoEnum.Y.isFlag());
        runningReportDataMapper.update(updateData, deleteWrapper);

        UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(RunningReport::getId, id)
            .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE);
        RunningReport runningReport = new RunningReport();
        RunningReportConfig config = null;
        // 更新运行报告的模版信息
        if (updateConfig) {
            QueryWrapper<RunningReportConfig> configQueryWrapper = new QueryWrapper<>();
            configQueryWrapper.lambda().eq(RunningReportConfig::getSpId, report.getSpId())
                .eq(RunningReportConfig::getIsDeleted, Constants.IS_DELETED_FALSE);
            config = runningReportConfigMapper.selectOne(configQueryWrapper);
            if (ObjectUtils.isEmpty(config)) {
                log.info("运行报告配置不存在,spId:{}", report.getSpId());
            }
            runningReport.setConfigId(config.getId());
            // 查看审核设置，未审核-无需审核
            // 重新生成报告不会更新审核状态
        } else {
            QueryWrapper<RunningReportConfig> configQueryWrapper = new QueryWrapper<>();
            configQueryWrapper.lambda().eq(RunningReportConfig::getSpId, report.getSpId())
                .eq(RunningReportConfig::getId, report.getConfigId());
            config = runningReportConfigMapper.selectOne(configQueryWrapper);
            if (ObjectUtils.isEmpty(config)) {
                log.info("运行报告配置不存在,spId:{},config:{}", report.getSpId(),report.getConfigId());
            }
        }
        runningReport.setAlarmPending(0);
        runningReport.setAlarmProcessing(0);
        runningReport.setAlarmProcessed(0);
        runningReport.setBrokenPending(0);
        runningReport.setBrokenProcessing(0);
        runningReport.setBrokenProcessed(0);
        runningReport.setOfflineTime(0L); // 离线时长
        runningReport.setOfflineTotal(0); // 离线记录总数
        runningReport.setReportContentType(Constants.BLANK);

        List<String> equipmentType = dtuMapper.queryEquipmentTypeByConsumerId(report.getConsumerId());
        // 查询设备类型相关信息
        StringBuilder equipmentTypeString = new StringBuilder();
        if (equipmentType.size() > 0) {
            for (String type : equipmentType) {
                if (!EquipmentType.POINT_TYPE_GAS_DETECTOR.getCode().equals(type)) {
                    equipmentTypeString.append(type).append(Constants.STR_COMMA);
                }
            }
        }
        runningReport.setDeviceType(equipmentTypeString.length() > 0 ? equipmentTypeString.deleteCharAt(equipmentTypeString.length() - 1).toString() : Constants.BLANK);

        // 报警和故障信息
        List<RunningReportData> reportDataList = new ArrayList<>();
        QueryWrapper<HistoryAlarm> historyAlarmQueryWrapper = new QueryWrapper<>();
        historyAlarmQueryWrapper.lambda().eq(HistoryAlarm::getConsumerId, report.getConsumerId())
                .eq(HistoryAlarm::getIsDeleted, 0)
                .ge(HistoryAlarm::getCreatedAt, startDate)
                .lt(HistoryAlarm::getCreatedAt, endDate);
        List<HistoryAlarm> historyAlarmList = historyAlarmMapper.selectList(historyAlarmQueryWrapper);
        // 判断报警
        if (historyAlarmList.size() > 0) {
            runningReport.setReportContentType(runningReport.getReportContentType() + ReportContentTypeEnum.ALARM.getCode() + Constants.STR_COMMA); //有报警
            historyAlarmList.stream().forEach(alarm -> {
                RunningReportData data = new RunningReportData();
                data.setReportId(report.getId());
                data.setImei(alarm.getIMEI());
                data.setAlarmAddress(dtuMapper.queryAddressByImei(alarm.getIMEI()));
                data.setAlarmTime(alarm.getCreatedAt());
                data.setAlarmType(0);
                data.setConcentration(alarm.getConcentration());

                if( AppealStateEnum.HANDLED_INSTALL.getCode().equals(alarm.getAppealStatus()) ||
                        AppealStateEnum.HANDLED_TEST.getCode().equals(alarm.getAppealStatus()) ){
                    data.setValveBrokenInfo("设备调试");
                }else if( AppealStateEnum.HANDLING.getCode().equals(alarm.getAppealStatus()) ||
                        AppealStateEnum.FINISHED.getCode().equals(alarm.getAppealStatus()) ){//转工单处理
                    data.setValveBrokenInfo("转线下处理");
                }else{
                    data.setValveBrokenInfo(StringUtils.isNotEmpty(alarm.getValveBrokenInfo()) ? alarmReasonMap.getOrDefault(alarm.getValveBrokenInfo(),Constants.BLANK) : Constants.BLANK);
                }

                data.setAppealTime(alarm.getAppealTime());
                if (alarm.getAppealStatus() == 0) {
                    // 报警未处理
                    data.setAppealStatus(0);
                    runningReport.setAlarmPending(runningReport.getAlarmPending() + 1);
                }else if (alarm.getAppealStatus() == 1 || alarm.getAppealStatus() == 4) {
                    // 报警处理中
                    data.setAppealStatus(1);
                    runningReport.setAlarmProcessing(runningReport.getAlarmProcessing() + 1);
                } else {
                    // 报警已处理
                    data.setAppealStatus(2);
                    runningReport.setAlarmProcessed(runningReport.getAlarmProcessed() + 1);
                }
                data.setSpId(consumer.getSpId());
                reportDataList.add(data);
            });
        }

        // 判断故障
        QueryWrapper<HistoryBroken> historyBrokenQueryWrapper = new QueryWrapper<>();
        historyBrokenQueryWrapper.lambda().eq(HistoryBroken::getConsumerId, report.getConsumerId())
                .eq(HistoryBroken::getIsDeleted, 0)
                .ge(HistoryBroken::getCreatedAt, startDate)
                .lt(HistoryBroken::getCreatedAt, endDate);
        List<HistoryBroken> historyBrokenList = historyBrokenMapper.selectList(historyBrokenQueryWrapper);
        if (historyBrokenList.size() > 0) {
            runningReport.setReportContentType(runningReport.getReportContentType() + ReportContentTypeEnum.BROKEN.getCode() + Constants.STR_COMMA); //有故障
            historyBrokenList.stream().forEach(broken -> {
                RunningReportData data = new RunningReportData();
                data.setReportId(report.getId());
                data.setImei(broken.getIMEI());
                data.setAlarmAddress(dtuMapper.queryAddressByImei(broken.getIMEI()));
                data.setAlarmTime(broken.getCreatedAt());
                data.setAlarmType(1);
                String reasonStr = broken.getReason();
                if( StringUtils.isNotEmpty(broken.getReason()) && StringUtils.isNotEmpty(broken.getValveBrokenInfo())){
                    reasonStr = broken.getReason()+";"+broken.getValveBrokenInfo();
                }else if( StringUtils.isEmpty(broken.getReason()) && StringUtils.isNotEmpty(broken.getValveBrokenInfo()) ){
                    reasonStr = broken.getValveBrokenInfo();
                }
                if(StringUtils.isNotEmpty(reasonStr)){
                    reasonStr = reasonStr.replaceAll("^;+|;+$", "");
                }
                data.setValveBrokenInfo(StringUtils.isEmpty(reasonStr) ? Constants.BLANK : reasonStr.replace(";正常", Constants.BLANK).replace("正常", Constants.BLANK));
                data.setAppealTime(broken.getAppealTime());
                if (broken.getAppealStatus() == 0) {
                    // 报警未处理
                    data.setAppealStatus(0);
                    runningReport.setBrokenPending(runningReport.getBrokenPending() + 1);
                }else if (broken.getAppealStatus() == 1 || broken.getAppealStatus() == 4) {
                    // 报警处理中
                    data.setAppealStatus(1);
                    runningReport.setBrokenProcessing(runningReport.getBrokenProcessing() + 1);
                } else {
                    // 报警已处理
                    data.setAppealStatus(2);
                    runningReport.setBrokenProcessed(runningReport.getBrokenProcessed() + 1);
                }
                data.setSpId(consumer.getSpId());
                reportDataList.add(data);
            });
        }

        // 判断离线
        // 判断离线  设备长时间未通讯，设备拔电，设备未上电激活
        // 需要 1.先打开离线统计的配置  2.设备不属于点型可燃气体探测器类型
        if (config.getIsOfflineConfig() != null && config.getIsOfflineConfig() == 0) {
            log.info("运行报告数据更新-开启离线统计", report.getSpId());
            InfluxDBConnect influxDBConnect = influxDBConfiguration.getInfluxDBConnect();
            Integer offlineInterval = config.getOfflineInterval() == null ? null : config.getOfflineInterval() * 60 * 60; // 离线间隔设置，单位秒
            // 查询该客户下所有的设备，不包含点型可燃气体探测器类型的
            LambdaQueryWrapper<Dtu> queryWrapper = new LambdaQueryWrapper();
            queryWrapper.eq(Dtu::getConsumerId,consumer.getId())
                .ne(Dtu::getEquipmentType, EquipmentType.POINT_TYPE_GAS_DETECTOR.getCode())
                .eq(Dtu::getIsDeleted,Constants.IS_DELETED_FALSE)
                .eq(Dtu::getSpId,consumer.getSpId());
            List<Dtu> dtuList = dtuMapper.selectList(queryWrapper);
            if (CollectionUtils.isNotEmpty(dtuList)) {
                for (Dtu dtu : dtuList) {
                    // 查询离线情况
                    // 查询本月开关机记录

                    List<RunningReportOnOffDTO> thisMonthOnOffDataList = getOnOffDataList(influxDBConnect, dtu, DateUtils.format(startDate, "yyyy-MM-dd HH:mm:ss"), DateUtils.format(endDate, "yyyy-MM-dd HH:mm:ss"));
                    if (CollectionUtils.isEmpty(thisMonthOnOffDataList)) {
                        log.info("运行报告数据更新-当月数据为空:{},{}", report.getReportDate(), dtu.getIMEI());
                        // 查询上一条
                        RunningReportOnOffDTO lastMonthOnOffData = getLastOnOffData(influxDBConnect, dtu, DateUtils.format(startDate, "yyyy-MM-dd HH:mm:ss"));
                        if (lastMonthOnOffData == null) {
                            log.info("运行报告数据更新-当月之前数据为空:{},{}", report.getReportDate(), dtu.getIMEI());
                            // 上一条是空，设备未上电激活
                            RunningReportData data = new RunningReportData();
                            data.setReportId(report.getId());
                            data.setImei(dtu.getIMEI());
                            data.setAlarmAddress(dtu.getInstallationPosition());
                            data.setAlarmType(2); // 离线
                            data.setValveBrokenInfo("设备未上电激活");
                            // 浓度值字段用来保存离线时间秒数
                            data.setOfflineTime(Long.valueOf(monthDay * 24 * 60 * 60));
                            runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                            runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                            data.setSpId(consumer.getSpId());
                            reportDataList.add(data);
                        }else if (lastMonthOnOffData != null && lastMonthOnOffData.isOffline()) {
                            log.info("运行报告数据更新-当月数据不为空且是离线:{},{}", report.getReportDate(), dtu.getIMEI());
                            // 上一条是离线
                            // 正常离线 / 周期性离线 + 离线配置开启，周期性离线计入统计
                            if (lastMonthOnOffData.getOfflineType() == 0 ||
                                    (lastMonthOnOffData.getOfflineType() == 1 && config.getOfflineInclude() == 1)) {
                                // 正常离线,离线时间为当月时长
                                RunningReportData data = new RunningReportData();
                                data.setReportId(report.getId());
                                data.setImei(dtu.getIMEI());
                                data.setAlarmAddress(dtu.getInstallationPosition());
                                data.setAlarmTime(lastMonthOnOffData.getTime());
                                data.setAlarmType(2); // 离线
                                data.setValveBrokenInfo(lastMonthOnOffData.getOfflineType() == 0 ? "设备拔电" : "设备长时间未通讯");
                                data.setOfflineTime(Long.valueOf(monthDay * 24 * 60 * 60));
                                data.setOfflineExtend(1); // 跨月
                                data.setAlarmTime(lastMonthOnOffData.getTime());
                                runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                data.setSpId(consumer.getSpId());
                                reportDataList.add(data);
                            }
                        }
                        // 上一条是在线，本月没有，那就不会有离线时间,不会计入明细

                    } else {
                        log.info("运行报告数据更新-当月数据不为空:{}", JSONObject.toJSONString(thisMonthOnOffDataList));
                        // 本月数据不为空
                        // 判断也没有之前的数据，来判断是不是首次上电激活
                        boolean activation = false;
                        RunningReportOnOffDTO lastMonthOnOffData = getLastOnOffData(influxDBConnect, dtu, DateUtils.format(startDate, "yyyy-MM-dd HH:mm:ss"));
                        RunningReportOnOffDTO nextMonthOnOffData = getNextOnOffData(influxDBConnect, dtu, DateUtils.format(endDate, "yyyy-MM-dd HH:mm:ss"));
                        if (lastMonthOnOffData == null) {
                            activation = true;
                        }
                        // 把上一个月的最后一条数据和下一个月的第一条数据组装进来
                        boolean lastOffline = false;
                        Integer lastOfflineType = 0;
                        Date lastTime = null;
                        Long lastSecond = 0L;
                        assembleOnOffDataList(thisMonthOnOffDataList, lastMonthOnOffData, nextMonthOnOffData);
                        for (int i = 0; i < thisMonthOnOffDataList.size(); i++) {
                            if (i == 0) {
                                // 第一条
                                lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                lastTime = thisMonthOnOffDataList.get(i).getTime();
                                lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                // 如果有未激活标记，首次需要登记设备未上电激活离线数据
                                if (activation) {
                                    RunningReportData data = new RunningReportData();
                                    data.setReportId(report.getId());
                                    data.setImei(dtu.getIMEI());
                                    data.setAlarmAddress(dtu.getInstallationPosition());
                                    data.setAlarmType(2); // 离线
                                    data.setValveBrokenInfo("设备未上电激活");
                                    data.setOfflineTime((endSecond > thisMonthOnOffDataList.get(i).getSecond() ? thisMonthOnOffDataList.get(i).getSecond() : endSecond) - startSecond );
                                    runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                    runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                    data.setSpId(consumer.getSpId());
                                    reportDataList.add(data);
                                }
                            } else {
                                // 不是第一条
                                if (thisMonthOnOffDataList.get(i).isOffline()) {
                                    // 关机
                                    // 如果上一条是开机  不需要计入离线，但需要更新
                                    // 如果上一条是关机  真实关机  周期性关机 不计入离线
                                    // 真实关机-真实关机  不更新
                                    // 真实关机-周期性关机 不更新
                                    // 周期性关机 -真实关机 更新
                                    // 周期性关机-周期性关机  不更新
                                    if ((lastOffline && lastOfflineType == 1 && thisMonthOnOffDataList.get(i).getOfflineType() == 0)
                                            || !lastOffline) {
                                        lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                        lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                        lastTime = thisMonthOnOffDataList.get(i).getTime();
                                        lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                    }
                                } else {
                                    // 开机
                                    // 如果上一条是开机 不需要计入离线，也不需要更新
                                    // 如果上一条是关机
                                    if (lastOffline) {
                                        // 上一条是关机
                                        if (lastOfflineType == 0) {
                                            // 上报离线 没有设置计算时间间隔，或者离线间隔大于设置的
                                            if (offlineInterval == null || thisMonthOnOffDataList.get(i).getSecond() - lastSecond > offlineInterval) {
                                                RunningReportData data = new RunningReportData();
                                                data.setReportId(report.getId());
                                                data.setImei(dtu.getIMEI());
                                                data.setAlarmAddress(dtu.getInstallationPosition());
                                                data.setAlarmTime(lastTime);
                                                data.setAlarmType(2); // 离线
                                                data.setValveBrokenInfo("设备拔电");
                                                data.setOfflineTime((endSecond > thisMonthOnOffDataList.get(i).getSecond() ? thisMonthOnOffDataList.get(i).getSecond() : endSecond) -
                                                        (startSecond > lastSecond ? startSecond : lastSecond));
                                                if (startSecond > lastSecond) {
                                                    data.setOfflineExtend(1); // 跨月
                                                }
                                                runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                data.setSpId(consumer.getSpId());
                                                reportDataList.add(data);
                                                lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                                lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                                lastTime = thisMonthOnOffDataList.get(i).getTime();
                                                lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                            }
                                        } else if (lastOfflineType == 1) {
                                            // 周期性离线,判断
                                            if (config.getOfflineInclude() == 1) {
                                                RunningReportData data = new RunningReportData();
                                                data.setReportId(report.getId());
                                                data.setImei(dtu.getIMEI());
                                                data.setAlarmAddress(dtu.getInstallationPosition());
                                                data.setAlarmTime(lastTime);
                                                data.setAlarmType(2); // 离线
                                                data.setValveBrokenInfo("设备长时间未通讯");
                                                data.setOfflineTime((endSecond > thisMonthOnOffDataList.get(i).getSecond() ? thisMonthOnOffDataList.get(i).getSecond() : endSecond) -
                                                        (startSecond > lastSecond ? startSecond : lastSecond));
                                                if (startSecond > lastSecond) {
                                                    data.setOfflineExtend(1); // 跨月
                                                }
                                                runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                                runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                                data.setSpId(consumer.getSpId());
                                                reportDataList.add(data);
                                                lastOffline = thisMonthOnOffDataList.get(i).isOffline();
                                                lastOfflineType = thisMonthOnOffDataList.get(i).getOfflineType();
                                                lastTime = thisMonthOnOffDataList.get(i).getTime();
                                                lastSecond = thisMonthOnOffDataList.get(i).getSecond();
                                            }
                                        }
                                    }
                                }
                            }
                            // 如果是最后一条，并且最后一条在本月，并且是关机
                            if (i > 0 && i == thisMonthOnOffDataList.size() -1 && nextMonthOnOffData == null
                                && thisMonthOnOffDataList.get(i).isOffline()) {
                                if (thisMonthOnOffDataList.get(i).getOfflineType() == 0) {
                                    // 必定超过记录时间，必定记录
                                    RunningReportData data = new RunningReportData();
                                    data.setReportId(report.getId());
                                    data.setImei(dtu.getIMEI());
                                    data.setAlarmAddress(dtu.getInstallationPosition());
                                    data.setAlarmTime(thisMonthOnOffDataList.get(i).getTime());
                                    data.setAlarmType(2); // 离线
                                    data.setValveBrokenInfo("设备拔电");
                                    data.setOfflineTime(endSecond - thisMonthOnOffDataList.get(i).getSecond());
                                    runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                    runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                    data.setSpId(consumer.getSpId());
                                    reportDataList.add(data);
                                } else if (thisMonthOnOffDataList.get(i).getOfflineType() == 1) {
                                    // 周期性离线
                                    if (config.getOfflineInclude() == 1) {
                                        RunningReportData data = new RunningReportData();
                                        data.setReportId(report.getId());
                                        data.setImei(dtu.getIMEI());
                                        data.setAlarmAddress(dtu.getInstallationPosition());
                                        data.setAlarmTime(thisMonthOnOffDataList.get(i).getTime());
                                        data.setAlarmType(2); // 离线
                                        data.setValveBrokenInfo("设备长时间未通讯");
                                        data.setOfflineTime(endSecond - thisMonthOnOffDataList.get(i).getSecond());
                                        runningReport.setOfflineTime(runningReport.getOfflineTime() + data.getOfflineTime());
                                        runningReport.setOfflineTotal(runningReport.getOfflineTotal() + 1);
                                        data.setSpId(consumer.getSpId());
                                        reportDataList.add(data);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }


        // 报告内容
        if (runningReport.getOfflineTotal() > 0) {
            runningReport.setReportContentType(runningReport.getReportContentType() + ReportContentTypeEnum.OFFLINE.getCode() + Constants.STR_COMMA); //有报警
        }
        if (StringUtils.isBlank(runningReport.getReportContentType())) {
            runningReport.setReportContentType(ReportContentTypeEnum.NO_ALARM.getCode().toString());
        } else {
            runningReport.setReportContentType(runningReport.getReportContentType().substring(0, runningReport.getReportContentType().length() - 1));
        }
        runningReport.setUpdateStatus(2); // 更新完成
        runningReport.setUpdatedAt(new Date());  // 报告更新时间
        log.info("数据更新中,runningReport:{}", runningReport.toString());
        this.update(runningReport, updateWrapper);
        runningReportDataService.saveBatch(reportDataList);

    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param auditConfigList
     * @return
     */
    public Map<String, List<Integer>> getNoAuditConfigMap(List<RunningReportAuditConfig> auditConfigList) {

        Map<String, List<Integer>> noAuditConfigMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(auditConfigList)) {
            for (RunningReportAuditConfig runningReportAuditConfig : auditConfigList) {
                List<String> custTypeList = getCustTypeList(runningReportAuditConfig.getCustType());
                List<Integer> alarmStatusList = getAlarmStatus(runningReportAuditConfig.getAlarmStatus());
                for (String custType : custTypeList) {
                    for (Integer alarmStatus : alarmStatusList) {
                        if (noAuditConfigMap.get(custType) == null) {
                            noAuditConfigMap.put(custType, new ArrayList<>());
                        }
                        noAuditConfigMap.get(custType).add(alarmStatus);

                    }
                }

            }
        }
        return noAuditConfigMap;
    }

    /**
     * 根据spId获取用户类型列表
     * @param custType
     * @return
     */
    public List<String> getCustTypeList(String custType) {
        if (StringUtils.isNotBlank(custType)) {
            return Arrays.asList(custType);
        }

        String spId = ApplicationUtils.getWorkingSpId();
        List<String> custTypes = consumerMapper.selectUserType(spId);
        if (CollectionUtils.isNotEmpty(custTypes)) {
            custTypes.remove("");
            // 其他
            if (consumerMapper.selectUserTypeCount(spId, "其他") > 0) {
                custTypes.add("其他");
            }
            // 未知
            if (consumerMapper.selectUserTypeCount(spId, "未知") > 0) {
                custTypes.add("未知");
            }
        }

        return custTypes;
    }

    /**
     * 根据spId获取用户类型列表
     * @return
     */
    public List<Integer> getAlarmStatus(Integer alarmStatus) {
        List<Integer> alarmStatusList = new ArrayList<>();
        if (alarmStatus == 0) {
            alarmStatusList.addAll(Arrays.asList(1,2,3,4));
        } else {
            alarmStatusList.add(alarmStatus);
        }

        return alarmStatusList;
    }

    @Override
    public void updateData(Integer id) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            RunningReport report = this.getById(id);
            if (ObjectUtils.isEmpty(report)) {
                throw new BizException("运行报告不存在");
            }
            if (report.getCheckStatus() != null && (report.getCheckStatus() == 1 || report.getCheckStatus() == 2)) {
                throw new BizException(report.getCheckStatus() == 1 ? "运行报告已审核" : "运行报告无需审核");
            }
            if (report.getUpdateStatus() != null && report.getUpdateStatus() == 1) {
                throw new BizException("运行报告数据更新中");
            }
            // 更新中
            UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(RunningReport::getId, id)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .set(RunningReport::getUpdateStatus, 1);
            this.update(updateWrapper);

            executor.submit(() -> {
                updateReportData(id, false);
            });
            vo.setDetail("成功");
            vo.setCommonInfo(String.valueOf(report.getConsumerId()));
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }

    }

    @Override
    public Integer batchUpdateData(List<Integer> ids) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().in(RunningReport::getId, ids)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .set(RunningReport::getUpdateStatus, 1);
            this.update(updateWrapper);

            executor.submit(() -> {
                for (Integer id : ids) {
                    updateReportData(id, false);
                }
            });

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
            return ids.size();
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }

    }

    @Override
    public Integer allUpdateData(String reportDate) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            // 需要更新的
            QueryWrapper<RunningReport> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .eq(RunningReport::getCheckStatus, 0)
                    .ne(RunningReport::getUpdateStatus, 1);
            List<RunningReport> runningReportList = this.list(queryWrapper);
            List<Integer> ids  = runningReportList.stream()
                    .map(RunningReport::getId).distinct().collect(Collectors.toList());
            // 更新中
            UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().in(RunningReport::getId, ids)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .set(RunningReport::getUpdateStatus, 1);
            this.update(updateWrapper);

            if (ids.size() > 0) {

                executor.submit(() -> {
                    for (Integer id : ids) {
                        updateReportData(id, false);
                    }
                });
            }

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
            return ids.size();
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }

    }

    @Override
    public void check(Integer id) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            RunningReport report = this.getById(id);
            if (ObjectUtils.isEmpty(report)) {
                throw new BizException("运行报告不存在");
            }
            if (report.getCheckStatus() != null && (report.getCheckStatus() == 1 || report.getCheckStatus() == 2)) {
                throw new BizException(report.getCheckStatus() == 1 ? "运行报告已审核" : "运行报告无需审核");
            }
            if (report.getUpdateStatus() != null && report.getUpdateStatus() == 1) {
                throw new BizException("运行报告数据更新中");
            }
            report.setCheckStatus(1);
            this.updateById(report);
            // 查询是否开启设备运行报告的配置
            BusinessNotice runningReportNotice = noticeService.getByCode(BusinessNoticeParam.H5_RUNNING_RECORD.getCode(), spId);
            log.info("runningReportCheck:{}", JSONObject.toJSONString(runningReportNotice));
            if (runningReportNotice != null &&  "ON".equals(runningReportNotice.getParamValue())){
                pushMsg(report);
            }

            vo.setDetail("成功");
            vo.setCommonInfo(String.valueOf(report.getConsumerId()));
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            //LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }

    }

    @Override
    public Integer batchCheck(List<Integer> ids) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().in(RunningReport::getId, ids)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .set(RunningReport::getCheckStatus, 1);
            this.update(updateWrapper);
            //查询出来所有 的运行报告
            QueryWrapper<RunningReport> selectWrapper = new QueryWrapper<>();
            selectWrapper.lambda().in(RunningReport::getId, ids)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId);
            List<RunningReport> runningReports = this.list(selectWrapper);
            BusinessNotice runningReportNotice = noticeService.getByCode(BusinessNoticeParam.H5_RUNNING_RECORD.getCode(), spId);
            log.info("runningReportCheck:{}", JSONObject.toJSONString(runningReportNotice));
            if (runningReportNotice != null &&  "ON".equals(runningReportNotice.getParamValue())){
                if (CollectionUtils.isNotEmpty(runningReports)) {
                    for (RunningReport runningReport : runningReports) {
                        pushMsg(runningReport);
                    }
                }
            }

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
            return ids.size();
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }
    }

    @Override
    public Integer allCheck(String reportDate) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            QueryWrapper<RunningReport> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .eq(RunningReport::getCheckStatus, 0);
            List<RunningReport> list = this.list(queryWrapper);
            List<Integer> ids = list.stream().map(RunningReport::getId).collect(Collectors.toList());

            if (ids.size() > 0) {
                UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().in(RunningReport::getId, ids)
                        .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                        .eq(RunningReport::getSpId, spId)
                        .set(RunningReport::getCheckStatus, 1);
                this.update(updateWrapper);
                BusinessNotice runningReportNotice = noticeService.getByCode(BusinessNoticeParam.H5_RUNNING_RECORD.getCode(), spId);
                log.info("runningReportCheck:{}", JSONObject.toJSONString(runningReportNotice));
                if (runningReportNotice != null &&  "ON".equals(runningReportNotice.getParamValue())){
                    for (RunningReport runningReport : list) {
                        pushMsg(runningReport);
                    }
                }
            }

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
            return ids.size();
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }
    }

    @Override
    public void download(Integer id) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        init();

        try {
            RunningReport report = this.getById(id);
            if (ObjectUtils.isEmpty(report)) {
                throw new BizException("运行报告不存在");
            }
            if (report.getUpdateStatus() != null && report.getUpdateStatus() == 1) {
                throw new BizException("运行报告数据更新中");
            }
            Consumer consumer = consumerMapper.selectById(report.getConsumerId());
            if (ObjectUtils.isEmpty(consumer)) {
                throw new BizException("客户不存在");
            }
            Date date = new Date();
            Calendar c = Calendar.getInstance();
            c.setTime(DateUtils.toDate(report.getReportDate(), "yyyy-MM"));
            String remark = Constants.BLANK;
            if (StringUtils.isNotEmpty(consumer.getCustName()) || StringUtils.isNotEmpty(consumer.getSubsCode())) {
                remark = new StringBuilder().append(consumer.getCustName()).append(Constants.LEFT_BRACKET).append(consumer.getSubsCode()).append(Constants.RIGHT_BRACKET)
                    .append("设备运行报告").append(Constants.UNDERLINE).append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月").toString();
            } else {
                remark = new StringBuilder().append(Constants.LEFT_BRACKET).append(consumer.getId()).append(Constants.RIGHT_BRACKET)
                    .append("设备运行报告").append(Constants.UNDERLINE).append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月").toString();
            }
            QueryWrapper<FileExport> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq( FileExport::getExportCode, ExportCodeEnum.PDF_1.getCode())
                    .eq( FileExport::getRemark, remark )
                    .eq( FileExport::getSpId, spId )
                    .eq( FileExport::getIsDeleted,Constants.IS_DELETED_FALSE )
                    .between( FileExport::getCreatedAt, DateUtil.beginOfDay(date),DateUtil.endOfDay(date));
            queryWrapper.select( "count(*) as sum" );
            Map<String, Object> map = fileExportService.getMap( queryWrapper );
            String s = map.get( "sum" ).toString();
            int sum =Integer.parseInt( s )+1;
            FileExport record = new FileExport();
            record.setExportCode(ExportCodeEnum.PDF_1.getCode());
            // record.setExportName(ExportCodeEnum.PDF_1.getName());
            record.setFileName(new StringBuilder().append(remark).append(Constants.LEFT_BRACKET).append(sum).append(Constants.RIGHT_BRACKET).toString());
            record.setExportCreator(ApplicationUtils.getWorkingUser().getUsername());
            record.setCreatorName(ApplicationUtils.getWorkingUser().getName());
            record.setExportStatus("1");
            record.setRemark(remark);
            record.setSpId(spId);
            fileExportService.save(record);

            executor.submit(() -> {
                UpdateWrapper<FileExport> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().eq(FileExport::getId, record.getId());
                FileExport export = new FileExport();
                try {
                    RunningReportDetailResponse response = detail(id);
                    ByteArrayInputStream stream = createPdfAsByteArrayInputStream(response, export);
                    log.info("运行报告下载状态:{}",export.toString());
                    if (StringUtils.isNotEmpty(export.getExportStatus()) && "2".equals(export.getExportStatus())) {
                        // 上传
                        CommonResponse resp = fileStorage.uploadPublicFile(new StringBuilder().append(record.getFileName()).append(Constants.STR_STRIKETHROUGH).append(DateUtil.format(new Date(),"yyyyMMddHHmmss")).append(Constants.UNDERLINE).append(getRandom()).append(".pdf").toString(), stream);
                        if (resp.getCode() != null && resp.getCode() == 0) {
                            export.setExportUrl((String)resp.getData());
                        } else {
                            export.setExportStatus("3");
                            export.setExportDesc(resp.getMsg());
                        }

                        log.info("运行报告下载结果:{}",resp.toString());
                    }

                } catch (Exception e) {
                    export.setExportStatus("3");
                    export.setExportDesc(e.getMessage());
                    log.info("运行报告下载失败：{}", e.getMessage());
                    throw new RuntimeException(e);
                }
                fileExportService.update(export, updateWrapper);
            });

            vo.setDetail("成功");
            vo.setCommonInfo(String.valueOf(report.getConsumerId()));
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }
    }

    @Override
    public void batchDownload(List<Integer> ids) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        init();

        try {
            if (CollectionUtils.isEmpty(ids)) {
                throw new BizException("无运行报告可下载");
            }
            // 查看是否有文档处于更新数据中
            RunningReport runningReport = this.getById(ids.get(0));
            Date date = new Date();
            Calendar c = Calendar.getInstance();
            c.setTime(DateUtils.toDate(runningReport.getReportDate(), "yyyy-MM"));
            String remark = new StringBuilder().append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月")
                    .append("设备运行报告").append(Constants.UNDERLINE).append(DateUtils.format(date, "yyyyMMdd")).toString();
            QueryWrapper<FileExport> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq( FileExport::getExportCode, ExportCodeEnum.PDF_1.getCode())
                    .eq( FileExport::getRemark, remark )
                    .eq( FileExport::getSpId, spId )
                    .eq( FileExport::getIsDeleted,Constants.IS_DELETED_FALSE )
                    .between( FileExport::getCreatedAt, DateUtil.beginOfMonth(date),DateUtil.endOfMonth(date));
            queryWrapper.select( "count(*) as sum" );
            Map<String, Object> map = fileExportService.getMap( queryWrapper );
            String s = map.get( "sum" ).toString();
            int sum =Integer.parseInt( s )+1;
            FileExport record = new FileExport();
            record.setExportCode(ExportCodeEnum.PDF_1.getCode());
            // record.setExportName(ExportCodeEnum.PDF_1.getName());
            record.setFileName(new StringBuilder().append(remark).append(Constants.LEFT_BRACKET).append(sum).append(Constants.RIGHT_BRACKET).toString());
            record.setExportCreator(ApplicationUtils.getWorkingUser().getUsername());
            record.setCreatorName(ApplicationUtils.getWorkingUser().getName());
            record.setExportStatus("1");
            record.setRemark(remark);
            record.setSpId(spId);
            fileExportService.save(record);
            executor.submit(() -> {
                // 最外层文件夹
                String fileDir = FILE_STORAGE_PATH + remark;
                File dir = new File(fileDir);
                if (!dir.exists() || !dir.isDirectory()) {
                    dir.mkdirs();
                }
                UpdateWrapper<FileExport> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().eq(FileExport::getId, record.getId());
                FileExport export = new FileExport();
                try {
                    for (Integer id : ids) {
                        RunningReportDetailResponse response = detail(id);
                        ByteArrayInputStream stream = createPdfAsByteArrayInputStream(response, export);
                        log.info("运行报告下载状态:{}",export.toString());
                        if (StringUtils.isNotEmpty(export.getExportStatus()) && "2".equals(export.getExportStatus())) {
                            // 保存到本地
                            String tempName = Constants.BLANK;
                            if (StringUtils.isNotEmpty(response.getCustName()) || StringUtils.isNotEmpty(response.getSubsCode())) {
                                tempName = new StringBuilder().append(response.getCustName()).append(Constants.LEFT_BRACKET).append(response.getSubsCode()).append(Constants.RIGHT_BRACKET)
                                        .append("设备运行报告").append(Constants.UNDERLINE).append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月").toString();
                            } else {
                                tempName = new StringBuilder().append(Constants.LEFT_BRACKET).append(response.getConsumerId()).append(Constants.RIGHT_BRACKET)
                                        .append("设备运行报告").append(Constants.UNDERLINE).append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月").toString();
                            }
                            try (FileOutputStream fos = new FileOutputStream(new StringBuilder().append(fileDir).append(Constants.STR_SLASH).append(tempName)
                                    .append(Constants.STR_STRIKETHROUGH).append(DateUtil.format(new Date(),"yyyyMMddHHmmss")).append(".pdf").toString())) {
                                // 创建一个临时缓冲区
                                byte[] buffer = new byte[1024];
                                // 循环读取 ByteArrayInputStream 中的数据并写入到 FileOutputStream
                                int readCount;
                                while ((readCount = stream.read(buffer)) != -1) {
                                    fos.write(buffer, 0, readCount);
                                }
                                // 刷新并关闭输出流，确保所有数据被写入磁盘
                                fos.flush();
                            } catch (Exception e) {
                                export.setExportStatus("3");
                                export.setExportDesc(e.getMessage());
                                log.info("运行报告下载失败：{}", e.getMessage());
                                throw new RuntimeException(e);
                            }

                        }
                    }
                    log.info("运行报告下载状态:{}",export.toString());
                    if (StringUtils.isNotEmpty(export.getExportStatus()) && "2".equals(export.getExportStatus())) {
                        // 压缩本地文件夹
                        String zipName = new StringBuilder().append(remark).append(".zip").toString();
                        String zipPath = "";
                        try {
                            ZipUtil.preZip(fileDir, FILE_ZIP_PATH, zipName);
                            zipPath = new StringBuilder().append(FILE_ZIP_PATH).append(zipName).toString();
                        }catch (Exception e) {
                            export.setExportStatus("3");
                            export.setExportDesc(e.getMessage());
                            log.info("运行报告下载失败：{}", e.getMessage());
                            throw new BizException(e.getMessage());
                        }

                        // 将文件转换为byte数组
                        File zip = new File(zipPath);
                        byte[] fileBytes = new byte[(int) zip.length()];

                        try (FileInputStream fis = new FileInputStream(zip)) {
                            fis.read(fileBytes);
                        }

                        // 使用byte数组创建ByteArrayInputStream
                        ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
                        CommonResponse resp = fileStorage.uploadPublicFile(new StringBuilder().append(record.getFileName()).append(Constants.STR_STRIKETHROUGH).append(DateUtil.format(new Date(),"yyyyMMddHHmmss")).append(Constants.UNDERLINE).append(getRandom()).append(".zip").toString(), bais);
                        if (resp.getCode() != null && resp.getCode() == 0) {
                            export.setExportUrl((String)resp.getData());
                        } else {
                            export.setExportStatus("3");
                            export.setExportDesc(resp.getMsg());
                        }
                        // 删除export文件夹和zip文件夹
                        try {
                            FileUtils.deleteDirectory(dir);
                        } catch (IOException e) {
                            export.setExportStatus("3");
                            export.setExportDesc(e.getMessage());
                            log.info("运行报告下载失败：{}", e.getMessage());
                            throw new RuntimeException(e);
                        }
                        zip.delete();

                        log.info("运行报告下载结果:{}",resp.toString());
                    }

                } catch (Exception e) {
                    export.setExportStatus("3");
                    export.setExportDesc(e.getMessage());
                    log.info("运行报告下载失败：{}", e.getMessage());
                    throw new RuntimeException(e);
                }
                fileExportService.update(export, updateWrapper);
            });

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }


    }

    @Override
    public void allDownload(String reportDate) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        init();
        try {
            QueryWrapper<RunningReport> queryListWrapper = new QueryWrapper<>();
            queryListWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                    .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                    .eq(RunningReport::getSpId, spId)
                    .ne(RunningReport::getUpdateStatus, 1);
            List<RunningReport> list = this.list(queryListWrapper);
            List<Integer> ids = list.stream().map(RunningReport::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(ids)) {
                throw new BizException("无运行报告可下载");
            }
            RunningReport runningReport = this.getById(ids.get(0));
            Date date = new Date();
            Calendar c = Calendar.getInstance();
            c.setTime(DateUtils.toDate(runningReport.getReportDate(), "yyyy-MM"));
            String remark = new StringBuilder().append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月")
                    .append("设备运行报告").append(Constants.UNDERLINE).append(DateUtils.format(date, "yyyyMMdd")).toString();
            QueryWrapper<FileExport> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().eq( FileExport::getExportCode, ExportCodeEnum.PDF_1.getCode())
                    .eq( FileExport::getRemark, remark )
                    .eq( FileExport::getSpId, spId )
                    .eq( FileExport::getIsDeleted,Constants.IS_DELETED_FALSE )
                    .between( FileExport::getCreatedAt, DateUtil.beginOfMonth(date),DateUtil.endOfMonth(date));
            queryWrapper.select( "count(*) as sum" );
            Map<String, Object> map = fileExportService.getMap( queryWrapper );
            String s = map.get( "sum" ).toString();
            int sum =Integer.parseInt( s )+1;
            FileExport record = new FileExport();
            record.setExportCode(ExportCodeEnum.PDF_1.getCode());
            // record.setExportName(ExportCodeEnum.PDF_1.getName());
            record.setFileName(new StringBuilder().append(remark).append(Constants.LEFT_BRACKET).append(sum).append(Constants.RIGHT_BRACKET).toString());
            record.setExportCreator(ApplicationUtils.getWorkingUser().getUsername());
            record.setCreatorName(ApplicationUtils.getWorkingUser().getName());
            record.setExportStatus("1");
            record.setRemark(remark);
            record.setSpId(spId);
            fileExportService.save(record);
            executor.submit(() -> {
                // 最外层文件夹
                String fileDir = FILE_STORAGE_PATH + remark;
                File dir = new File(fileDir);
                if (!dir.exists() || !dir.isDirectory()) {
                    dir.mkdirs();
                }
                UpdateWrapper<FileExport> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().eq(FileExport::getId, record.getId());
                FileExport export = new FileExport();
                try {
                    for (Integer id : ids) {
                        RunningReportDetailResponse response = detail(id);
                        ByteArrayInputStream stream = createPdfAsByteArrayInputStream(response, export);
                        log.info("运行报告下载状态:{}",export.toString());
                        if (StringUtils.isNotEmpty(export.getExportStatus()) && "2".equals(export.getExportStatus())) {
                            // 保存到本地
                            String tempName = Constants.BLANK;
                            if (StringUtils.isNotEmpty(response.getCustName()) || StringUtils.isNotEmpty(response.getSubsCode())) {
                                tempName = new StringBuilder().append(response.getCustName()).append(Constants.LEFT_BRACKET).append(response.getSubsCode()).append(Constants.RIGHT_BRACKET)
                                        .append("设备运行报告").append(Constants.UNDERLINE).append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月").toString();
                            } else {
                                tempName = new StringBuilder().append(Constants.LEFT_BRACKET).append(response.getConsumerId()).append(Constants.RIGHT_BRACKET)
                                        .append("设备运行报告").append(Constants.UNDERLINE).append(c.get(Calendar.YEAR)).append("年").append(c.get(Calendar.MONTH) + 1).append("月").toString();
                            }
                            try (FileOutputStream fos = new FileOutputStream(new StringBuilder().append(fileDir).append(Constants.STR_SLASH).append(tempName)
                                    .append(Constants.STR_STRIKETHROUGH).append(DateUtil.format(new Date(),"yyyyMMddHHmmss")).append(".pdf").toString())) {
                                // 创建一个临时缓冲区
                                byte[] buffer = new byte[1024];
                                // 循环读取 ByteArrayInputStream 中的数据并写入到 FileOutputStream
                                int readCount;
                                while ((readCount = stream.read(buffer)) != -1) {
                                    fos.write(buffer, 0, readCount);
                                }
                                // 刷新并关闭输出流，确保所有数据被写入磁盘
                                fos.flush();
                            } catch (Exception e) {
                                export.setExportStatus("3");
                                export.setExportDesc(e.getMessage());
                                log.info("运行报告下载失败：{}", e.getMessage());
                                throw new RuntimeException(e);
                            }

                        }
                    }
                    log.info("运行报告下载状态:{}",export.toString());
                    if (StringUtils.isNotEmpty(export.getExportStatus()) && "2".equals(export.getExportStatus())) {
                        // 压缩本地文件夹
                        String zipName = new StringBuilder().append(remark).append(".zip").toString();
                        String zipPath = "";
                        try {
                            ZipUtil.preZip(fileDir, FILE_ZIP_PATH, zipName);
                            zipPath = new StringBuilder().append(FILE_ZIP_PATH).append(zipName).toString();
                        }catch (Exception e) {
                            export.setExportStatus("3");
                            export.setExportDesc(e.getMessage());
                            log.info("运行报告下载失败：{}", e.getMessage());
                            throw new BizException(e.getMessage());
                        }

                        // 将文件转换为byte数组
                        File zip = new File(zipPath);
                        byte[] fileBytes = new byte[(int) zip.length()];

                        try (FileInputStream fis = new FileInputStream(zip)) {
                            fis.read(fileBytes);
                        }

                        // 使用byte数组创建ByteArrayInputStream
                        ByteArrayInputStream bais = new ByteArrayInputStream(fileBytes);
                        CommonResponse resp = fileStorage.uploadPublicFile(new StringBuilder().append(record.getFileName()).append(Constants.STR_STRIKETHROUGH).append(DateUtil.format(new Date(),"yyyyMMddHHmmss")).append(".zip").toString(), bais);
                        if (resp.getCode() != null && resp.getCode() == 0) {
                            export.setExportUrl((String)resp.getData());
                        } else {
                            export.setExportStatus("3");
                            export.setExportDesc(resp.getMsg());
                        }
                        // 删除export文件夹和zip文件夹
                        try {
                            FileUtils.deleteDirectory(dir);
                        } catch (IOException e) {
                            export.setExportStatus("3");
                            export.setExportDesc(e.getMessage());
                            log.info("运行报告下载失败：{}", e.getMessage());
                            throw new RuntimeException(e);
                        }
                        zip.delete();

                        log.info("运行报告下载结果:{}",resp.toString());
                    }

                } catch (Exception e) {
                    export.setExportStatus("3");
                    export.setExportDesc(e.getMessage());
                    log.info("运行报告下载失败：{}", e.getMessage());
                    throw new RuntimeException(e);
                }
                fileExportService.update(export, updateWrapper);
            });

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }
    }


    @Override
    public void regenerate(String reportDate) {
        String spId = ApplicationUtils.getWorkingSpId();
        LogVO vo = new LogVO();
        try {
            // 查看当前模版
            QueryWrapper<RunningReportConfig> configQueryWrapper = new QueryWrapper<>();
            configQueryWrapper.lambda().eq(RunningReportConfig::getIsDeleted,0)
                    .eq(RunningReportConfig::getSpId, spId);
            RunningReportConfig runningReportConfig = runningReportConfigService.getOne(configQueryWrapper);
            if (ObjectUtils.isEmpty(runningReportConfig)) {
                throw new BizException("运行报告配置不存在");
            }

            QueryWrapper<RunningReport> allQueryWrapper = new QueryWrapper<>();
            allQueryWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                    .eq(RunningReport::getIsDeleted, YesNoEnum.N.getCode())
                    .eq(RunningReport::getSpId, spId);
            Integer allNumber = runningReportMapper.selectCount(allQueryWrapper);
            QueryWrapper<RunningReport> unCheckQueryWrapper = new QueryWrapper<>();
            unCheckQueryWrapper.lambda().eq(RunningReport::getCheckStatus, 0)
                    .eq(RunningReport::getReportDate, reportDate)
                    .eq(RunningReport::getIsDeleted, YesNoEnum.N.getCode())
                    .eq(RunningReport::getSpId, spId);
            Integer checkNumber = runningReportMapper.selectCount(unCheckQueryWrapper);
            if (checkNumber > 0 && allNumber == checkNumber ) {
                // 更新中
                UpdateWrapper<RunningReport> updateWrapper = new UpdateWrapper<>();
                updateWrapper.lambda().eq(RunningReport::getReportDate, reportDate)
                        .eq(RunningReport::getIsDeleted, Constants.IS_DELETED_FALSE)
                        .eq(RunningReport::getSpId, spId)
                        .set(RunningReport::getUpdateStatus, 1);
                this.update(updateWrapper);
                List<RunningReport> runningReportList = this.list(unCheckQueryWrapper);
                List<Integer> ids  = runningReportList.stream()
                        .map(RunningReport::getId).distinct().collect(Collectors.toList());

                if (ids.size() > 0) {

                    executor.submit(() -> {
                        for (Integer id : ids) {
                            updateReportData(id, true);
                        }
                    });
                }
            } else {
                throw new BizException("存在已审核或无需审核的报告，请刷新");
            }

            vo.setDetail("成功");
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail("失败");
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }

    }

    public ByteArrayInputStream createPdfAsByteArrayInputStream(RunningReportDetailResponse response, FileExport export) throws DocumentException, IOException {
        log.info("运行报告下载中");
        // 创建一个用于存储PDF字节的输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 创建一个新的PDF文档
        Document document = new Document(PageSize.A4);
        Paragraph blankLine = new Paragraph("");
        blankLine.setSpacingBefore(10f); // 设置段前间距，可调整
        blankLine.setSpacingAfter(10f); // 设置段后间距，可调整
        Paragraph tableTitleBlankLine = new Paragraph("");
        tableTitleBlankLine.setSpacingBefore(5f); // 设置段前间距，可调整
        tableTitleBlankLine.setSpacingAfter(5f); // 设置段后间距，可调整
        BaseFont baseFont =BaseFont.createFont(FILE_FONT_PATH+"/simsun.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
        // BaseFont baseFont = BaseFont.createFont("SimSun", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
        Font headerFont = new Font(baseFont, 20, Font.BOLD, BaseColor.BLACK);
        Font contentFont = new Font(baseFont, 14, Font.NORMAL, BaseColor.BLACK);
        Font listTitleFont = new Font(baseFont, 17, Font.NORMAL, BaseColor.BLACK);
        Font tableContentFont = new Font(baseFont, 11, Font.NORMAL, BaseColor.BLACK);
        // 使用内存中的输出流创建PdfWriter实例
        PdfWriter pdfWriter =  PdfWriter.getInstance(document, byteArrayOutputStream);
        pdfWriter.setPageEvent(new CustomHeaderHandler());
        String header = new StringBuilder().append(Constants.HEADER_BLANK).append(response.getHeaderContent()).toString();
        // 打开文档以便添加内容
        document.open();

        Image headerImg = Image.getInstance(response.getHeaderLogo());
        headerImg.getAbsoluteX();
        log.info("headerImg.getAbsoluteX()={}", headerImg.getScaledWidth());
        log.info("headerImg.getAbsoluteY()={}", headerImg.getScaledHeight());
        float widthInPoints = document.getPageSize().getWidth() - 72f;
        float imgWidth = (headerImg.getScaledWidth()/headerImg.getScaledHeight())*45f;
        float f1 = imgWidth / widthInPoints;
        headerImg.scaleToFit(imgWidth, 45f); // 可选，按需求调整图片大小
        float[] columnWidths1 = new float[2];
        columnWidths1[0] = f1+0.03f;
        columnWidths1[1] = 1- columnWidths1[0];
        PdfPTable headerTable1 = new PdfPTable(columnWidths1);
        headerTable1.setWidthPercentage(100);
        PdfPCell headerCell = new PdfPCell();
        headerCell.addElement(headerImg);
        headerCell.setBorder(PdfPCell.NO_BORDER);
        headerCell.setHorizontalAlignment(Element.ALIGN_LEFT); // 单元格内容居中对齐
        headerCell.setVerticalAlignment(Element.ALIGN_MIDDLE);
        PdfPCell headerCell2 = new PdfPCell();
        Chunk chunkText = new Chunk(response.getHeaderContent(), headerFont);
        headerCell2.addElement(chunkText);
        headerCell2.setBorder(PdfPCell.NO_BORDER);
        headerCell2.setHorizontalAlignment(Element.ALIGN_LEFT); // 单元格内容居中对齐
        headerTable1.addCell(headerCell);
        headerTable1.addCell(headerCell2);

        String pieImgPath = Constants.BLANK;
        String barImgPath = Constants.BLANK;
        final Integer[] isSort = {0};

        if (!response.getReportContentType().equals(ReportContentTypeEnum.NO_ALARM.getCode().toString())) {
            // 存在异常
            // 报警总结
            if (response.getIsAlarmSummary() == ShowAndSelectEnum.SHOW.getCode()) {
                // 页眉
                if (response.getHeaderShow() == ShowAndSelectEnum.SHOW.getCode()) {
//                    Image img = Image.getInstance(response.getHeaderLogo()); // 替换为你的图片路径
//                    img.scaleToFit(40f, 40f); // 可选，按需求调整图片大小
//                    Chunk chunkText = new Chunk(header, headerFont);
//                    Phrase phrase = new Phrase();
//                    phrase.add(new Chunk(img, 0, 0, true)); // 图片不换行，true表示允许图片打断文字
//                    phrase.add(chunkText);
//                    document.add(phrase);
//                    document.add(blankLine);
                    document.add(headerTable1);
                    document.add(blankLine);
                }
                // 内容
                document.add(new Paragraph(response.getAlarmSummaryContent(), contentFont));
                document.add(blankLine);
                // 标题
                Paragraph alarmSummaryTitle = new Paragraph(response.getAlarmSummaryTitle(), listTitleFont);
                alarmSummaryTitle.setAlignment(Paragraph.ALIGN_CENTER);
                document.add(alarmSummaryTitle);
                document.add(tableTitleBlankLine);
                // 列表
                if (CollectionUtils.isNotEmpty(response.getAlarmSummaryColumns())) {
                    // 创建一个简单的表格
                    PdfPTable table = new PdfPTable(response.getAlarmSummaryColumns().size()); //表格长度
                    table.setWidthPercentage(100); // 宽度占整个页面的100%
                    for (PageColumns column : response.getAlarmSummaryColumns()) {
                        PdfPCell cellHeader = new PdfPCell(new Phrase(column.getTitle(), tableContentFont));
                        cellHeader.setHorizontalAlignment(Element.ALIGN_CENTER);
                        cellHeader.setVerticalAlignment(Element.ALIGN_MIDDLE);
                        cellHeader.setPaddingTop(paddingTop);
                        cellHeader.setPaddingBottom(paddingBottom);
                        cellHeader.setBackgroundColor(new BaseColor(250, 250, 250));
                        table.addCell(cellHeader);
                    }
                    if (CollectionUtils.isNotEmpty(response.getAlarmSummaryDatas())) {
                        // 添加数据行
                        for (RunningReportAlarmSummaryDTO data : response.getAlarmSummaryDatas()) { //
                            for (PageColumns column : response.getAlarmSummaryColumns()) {
                                if ("time".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getTime(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("alarmType".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getAlarmType(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("valveBrokenInfo".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getValveBrokenInfo(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("alarmNumber".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(String.valueOf(data.getAlarmNumber()), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("proportion".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getProportion(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("appealStatus".equals(column.getDataIndex())) {
                                    StringBuilder builder = new StringBuilder();
                                    if (data.getAlarmType().equals(ReportAlarmTypeEnum.OFFLINE.getName())) {
                                        builder.append(Constants.STR_STRIKETHROUGH);
                                    } else {
                                        if (data.getPendingNumber() != null && data.getPendingNumber() > 0) {
                                            builder.append("待处理（").append(data.getPendingNumber()).append("）\n");
                                        }
                                        if (data.getProcessingNumber() != null && data.getProcessingNumber() > 0) {
                                            builder.append("处理中（").append(data.getProcessingNumber()).append("）\n");
                                        }
                                        if (data.getProcessedNumber() != null && data.getProcessedNumber() > 0) {
                                            builder.append("已处理（").append(data.getProcessedNumber()).append("）\n");
                                        }
                                    }
                                    PdfPCell cellContent = new PdfPCell(new Phrase(builder.length() > 0 ? builder.deleteCharAt(builder.length() - 1).toString() : Constants.BLANK, tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                }
                            }
                        }
                    }
                    // 将表格添加到文档中
                    document.add(table);
                }
                // 图示
                if (response.getCategoryAnalysisShow() == ShowAndSelectEnum.SHOW.getCode()) {
                     StringBuilder alarmBroken = new StringBuilder();
                     if (response.getAlarmTotal() != null && response.getAlarmTotal() != 0) {
                         alarmBroken.append(Constants.RUNNING_REPORT_ALARM_BROKEN.replace("#number#", String.valueOf(response.getAlarmTotal()))
                             .replace("#name#", ReportAlarmTypeEnum.ALARM.getName())
                             .replace("#color#", ReportAlarmTypeEnum.ALARM.getColor()));
                     }
                    if (response.getBrokenTotal() != null && response.getBrokenTotal() != 0) {
                        alarmBroken.append(Constants.RUNNING_REPORT_ALARM_BROKEN.replace("#number#", String.valueOf(response.getBrokenTotal()))
                            .replace("#name#", ReportAlarmTypeEnum.BROKEN.getName())
                            .replace("#color#", ReportAlarmTypeEnum.BROKEN.getColor()));
                    }
                    if (response.getOfflineTotal() != null && response.getOfflineTotal() != 0) {
                        alarmBroken.append(Constants.RUNNING_REPORT_ALARM_BROKEN.replace("#number#", String.valueOf(response.getBrokenTotal()))
                            .replace("#name#", ReportAlarmTypeEnum.OFFLINE.getName())
                            .replace("#color#", ReportAlarmTypeEnum.OFFLINE.getColor()));
                    }
                    // 组织数据源的数据
                    String pieTxt = Constants.RUNNING_REPORT_ALARM_PIE.replace("#name#", new StringBuilder().append(response.getMonth()).append("月事件分析").toString())
                        .replace("#data#", alarmBroken.toString());

                    // 执行获取图片
                    // temp地址
                    // 真实地址
                    String pieTxtPath = new StringBuilder().append(FILE_DATA_TXT_PATH).append(SnowflakeUtil.getSnowflakeId()).append(".txt").toString();
                    File txt = new File(pieTxtPath);
                    if (!txt.exists()) {
                        txt.createNewFile();
                    }
                    log.info("txt:{}", pieTxtPath);
                    File txt3 = new File(pieTxtPath);
                    if (txt3.exists()) {
                        log.info("运行报告txt存在:{}", pieTxtPath);
                    } else {
                        log.info("运行报告txt不存在:{}", pieTxtPath);
                    }
                    try (BufferedWriter writer = new BufferedWriter(new FileWriter(pieTxtPath))) {
                        writer.write(pieTxt); // 写入文本
                        writer.newLine(); // 添加一个新行（可选，根据需要）
                        writer.flush(); // 刷新缓冲区，确保立即写入文件（可选，一般在关闭时自动完成）
                    } catch (IOException e) {
                        log.error("An error occurred while writing to the pie file: {}", e.getMessage());
                        e.printStackTrace();
                    }
                    String tempPiePath = new StringBuilder().append(FILE_ECHART_IMG_PATH).append(SnowflakeUtil.getSnowflakeId()).append(".png").toString();
                    String piePath = new StringBuilder().append(FILE_ECHART_IMG_PATH).append(SnowflakeUtil.getSnowflakeId()).append(".png").toString();

                    start(pieTxtPath, tempPiePath, piePath, "448", "400");

                    pieImgPath = piePath;
                    File txtDel = new File(pieTxtPath);
                    if (txtDel.exists()) {
                        log.info("运行报告txt存在:{}", pieTxtPath);
                        txtDel.delete();
                    }
                    File tempPieDel = new File(tempPiePath);
                    if (tempPieDel.exists()) {
                        log.info("运行报告临时图片存在:{}", tempPiePath);
                        tempPieDel.delete();
                    }
                }
                log.info("pdfdocument1");
                if (response.getSituationAnalysisShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    StringBuilder dataStr = new StringBuilder();
                    StringBuilder valueStr = new StringBuilder();
                    if (response.getSituationAnalysisMap() != null) {
                        response.getSituationAnalysisMap().forEach((key, value) -> {
                            if (key.length() > 8) {
                                isSort[0] = 1;
                            }

                            dataStr.append("'").append(key.indexOf("()") != -1 ? key.replace("()", "(原因为空)") : key).append("',");
                            valueStr.append("{value: ").append(value).append(",itemStyle: {color: '")
                                .append(ReportAlarmTypeEnum.getColorByName(key.substring(0,2))).append("'}},");

                        });
                    }
                    if (dataStr.length() > 0 && valueStr.length() > 0) {
                        log.info("柱状图");
                        // 组织数据源的数据
                        String pieTxt = Constants.RUNNING_REPORT_ALARM_BAR.replace("#name#", new StringBuilder().append(response.getMonth()).append("月事件原因分析").toString())
                                .replace("#data#", dataStr.deleteCharAt(dataStr.length() -1 ).toString())
                                .replace("#value#", valueStr.deleteCharAt(valueStr.length() -1 ).toString())
                                .replace("#sort#",  isSort[0] == 0 ? Constants.BLANK : "rotate: 30,")
                                .replace("#grid#",  isSort[0] == 0 ? Constants.BLANK : "  grid: { bottom: 150 },");
                        // 执行获取图片
                        // temp地址
                        // 真实地址
                        String pieTxtPath = new StringBuilder().append(FILE_DATA_TXT_PATH).append(SnowflakeUtil.getSnowflakeId()).append(".txt").toString();

                        try (BufferedWriter writer = new BufferedWriter(new FileWriter(pieTxtPath))) {
                            writer.write(pieTxt); // 写入文本
                            writer.newLine(); // 添加一个新行（可选，根据需要）
                            writer.flush(); // 刷新缓冲区，确保立即写入文件（可选，一般在关闭时自动完成）
                        } catch (IOException e) {
                            log.error("An error occurred while writing to the pie file: " + e.getMessage());
                            e.printStackTrace();
                        }
                        String tempPiePath = new StringBuilder().append(FILE_ECHART_IMG_PATH).append(SnowflakeUtil.getSnowflakeId()).append(".png").toString();
                        String piePath = new StringBuilder().append(FILE_ECHART_IMG_PATH).append(SnowflakeUtil.getSnowflakeId()).append(".png").toString();

                        String cmd = getCMD(pieTxtPath, tempPiePath, piePath);
                        log.info("运行报告饼图cmd:{}", cmd);
                        Integer width = 500;
                        Integer height = 400;
                        if (response.getSituationAnalysisMap().size() > 3) {
                            width = 170 * response.getSituationAnalysisMap().size();
                            height = 100 * response.getSituationAnalysisMap().size();
                            start(pieTxtPath, tempPiePath, piePath, isSort[0] == 0 ? String.valueOf(width) : (width > 750 ? String.valueOf(width) : "750"), isSort[0] == 0 ? "400" : "600");
                        } else {
                            start(pieTxtPath, tempPiePath, piePath, isSort[0] == 0 ? "500" : "750", isSort[0] == 0 ? "400" : "600");
                        }


                        barImgPath = piePath;

                        File txtDel = new File(pieTxtPath);
                        if (txtDel.exists()) {
                            log.info("运行报告txt存在:{}", pieTxtPath);
                            txtDel.delete();
                        }
                        File tempPieDel = new File(tempPiePath);
                        if (tempPieDel.exists()) {
                            log.info("运行报告临时图片存在:{}", tempPiePath);
                            tempPieDel.delete();
                        }
                    }
                }
                if (StringUtils.isNotEmpty(pieImgPath) && StringUtils.isNotEmpty(barImgPath)) {
                    // 两个都有
                    document.add(blankLine);
                    float width = 240f;
                    if (response.getSituationAnalysisMap().size() > 3) {
                        width = 80f * response.getSituationAnalysisMap().size();
                        if (width > widthInPoints) {
                            width = widthInPoints ;
                        }
                        Image pie1 = Image.getInstance(pieImgPath); // 替换为你的图片路径
                        pie1.scaleToFit(250f, 200f); // 可选，按需求调整图片大小
                        pie1.setAlignment(Image.MIDDLE);
                        document.add(pie1);
                        Image bar1 = Image.getInstance(barImgPath); // 替换为你的图片路径
                        bar1.scaleToFit(width, 200f); // 可选，按需求调整图片大小
                        bar1.setAlignment(Image.MIDDLE);
                        document.add(bar1);
                        document.newPage();
                    } else {
                        float[] columnWidths11 = {0.5f, 0.5f};
                        PdfPTable tablePie = new PdfPTable(columnWidths11);
                        tablePie.setWidthPercentage(100); // 设置表格宽度为页面宽度的100%
                        // 创建一个PdfPCell，设置其垂直对齐方式为居中
                        PdfPCell cell11 = new PdfPCell();
                        cell11.setBorder(PdfPCell.NO_BORDER);
                        Image pie1 = Image.getInstance(pieImgPath); // 替换为你的图片路径
                        pie1.scaleToFit(250f, 200f); // 可选，按需求调整图片大小
                        cell11.addElement(pie1);
                        tablePie.addCell(cell11);
                        PdfPCell cell22 = new PdfPCell();
                        cell22.setBorder(PdfPCell.NO_BORDER);
                        Image bar1 = Image.getInstance(barImgPath); // 替换为你的图片路径
                        bar1.scaleToFit(250f, 200f); // 可选，按需求调整图片大小
                        cell22.addElement(bar1);
                        tablePie.addCell(cell22);
                        document.add(tablePie);
                    }

                } else if (StringUtils.isNotEmpty(pieImgPath) || StringUtils.isNotEmpty(barImgPath)) {
                    // 只有一个
                    document.add(blankLine);
                    if (StringUtils.isNotEmpty(pieImgPath)) {
                        Image pie1 = Image.getInstance(pieImgPath); // 替换为你的图片路径
                        pie1.scaleToFit(240f, 200f); // 可选，按需求调整图片大小
                        pie1.setAlignment(Image.MIDDLE);
                        document.add(pie1);
                    }
                    float width = 240f;
                    if (response.getSituationAnalysisMap().size() > 3) {
                        width = 80f * width;
                    }
                    if (width > widthInPoints) {
                        width = widthInPoints ;
                    }
                    if (StringUtils.isNotEmpty(barImgPath)) {
                        Image bar1 = Image.getInstance(barImgPath); // 替换为你的图片路径
                        bar1.scaleToFit(width, 200f); // 可选，按需求调整图片大小
                        bar1.setAlignment(Image.MIDDLE);
                        document.add(bar1);
                    }

                }
                if (StringUtils.isNotEmpty(pieImgPath)) {
                    File pieDel = new File(pieImgPath);
                    if (pieDel.exists()) {
                        log.info("运行报告饼图存在:{}", pieDel);
                        pieDel.delete();
                    }
                }
                if (StringUtils.isNotEmpty(barImgPath)) {
                    File barDel = new File(barImgPath);
                    if (barDel.exists()) {
                        log.info("运行报告柱状图图存在:{}", barDel);
                        barDel.delete();
                    }
                }
            }
            // 报警明细
            if (response.getIsAlarmDetail() == ShowAndSelectEnum.SHOW.getCode()) {
                log.info("pdfdocument3");
                float[] columnWidths = new float[1];
                float columnFloat = 0f;
                if (CollectionUtils.isNotEmpty(response.getAlarmDetailDatas())) {
                    columnWidths = new float[response.getAlarmDetailColumns().size()];
                    for (int i = 0; i < response.getAlarmDetailColumns().size(); i++) {
                        if ("number".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            // 序号
                            columnWidths[i] = 0.1f;
                            columnFloat += 0.1f;
                        } else if ("imei".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.3f;
                            columnFloat += 0.3f;
                        } else if ("alarmAddress".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.2f;
                            columnFloat += 0.2f;
                        } else if ("alarmType".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.2f;
                            columnFloat += 0.2f;
                        } else if ("alarmTime".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.3f;
                            columnFloat += 0.3f;
                        } else if ("concentration".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.25f;
                            columnFloat += 0.25f;
                        } else if ("appealTime".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.3f;
                            columnFloat += 0.3f;
                        } else if ("appealStatus".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.2f;
                            columnFloat += 0.2f;
                        } else if ("valveBrokenInfo".equals(response.getAlarmDetailColumns().get(i).getDataIndex())) {
                            columnWidths[i] = 0.2f;
                            columnFloat += 0.2f;
                        }
                    }
                }
               log.info("columnFloat={}", columnFloat);
                if (columnFloat > 1.25f) {
                    document.setPageSize(PageSize.A4.rotate());
                }
                document.newPage();

                // 页眉
                if (response.getHeaderShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    float widthInPoints2 = document.getPageSize().getWidth() - 72f;
                    float f2 = imgWidth / widthInPoints2;

                    float[] columnWidths2 = new float[2];
                    columnWidths2[0] = f2+0.03f;
                    columnWidths2[1] = 1- columnWidths2[0];
                    PdfPTable headerTable2 = new PdfPTable(columnWidths2);
                    headerTable2.setWidthPercentage(100);
                    PdfPCell header2Cell = new PdfPCell();
                    header2Cell.addElement(headerImg);
                    header2Cell.setBorder(PdfPCell.NO_BORDER);
                    header2Cell.setHorizontalAlignment(Element.ALIGN_LEFT); // 单元格内容居中对齐
                    header2Cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
                    PdfPCell header2Cell2 = new PdfPCell();
                    header2Cell2.addElement(chunkText);
                    header2Cell2.setBorder(PdfPCell.NO_BORDER);
                    header2Cell2.setHorizontalAlignment(Element.ALIGN_LEFT); // 单元格内容居中对齐

                    headerTable2.addCell(header2Cell);
                    headerTable2.addCell(header2Cell2);
                    document.add(headerTable2);
                    document.add(blankLine);
                }
                // 标题
                Paragraph alarmDetailTitle = new Paragraph(response.getAlarmDetailTitle(), listTitleFont);
                alarmDetailTitle.setAlignment(Paragraph.ALIGN_CENTER);
                document.add(alarmDetailTitle);
                // 户号 户名 户址
                if (response.getAlarmDetailCodeShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    document.add(new Paragraph(new StringBuilder().append("户名：").append(response.getSubsCode()).toString(), contentFont));
                }
                if (response.getAlarmDetailNameShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    document.add(new Paragraph(new StringBuilder().append("户号：").append(response.getCustName()).toString(), contentFont));
                }
                if (response.getAlarmDetailAddressShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    document.add(new Paragraph(new StringBuilder().append("户址：").append(response.getCustAddress()).toString(), contentFont));
                }
                document.add(blankLine);
                // 列表
                if (CollectionUtils.isNotEmpty(response.getAlarmDetailDatas())) {
                    PdfPTable table = new PdfPTable(columnWidths); //表格长度
                    table.setWidthPercentage(100); // 宽度占整个页面的100%
                    for (PageColumns column : response.getAlarmDetailColumns()) {
                        PdfPCell cellHeader = new PdfPCell(new Phrase(column.getTitle(), tableContentFont));
                        cellHeader.setHorizontalAlignment(Element.ALIGN_CENTER);
                        cellHeader.setVerticalAlignment(Element.ALIGN_MIDDLE);
                        cellHeader.setPaddingTop(paddingTop);
                        cellHeader.setPaddingBottom(paddingBottom);
                        cellHeader.setBackgroundColor(new BaseColor(250, 250, 250));
                        table.addCell(cellHeader);
                    }
                    if (CollectionUtils.isNotEmpty(response.getAlarmDetailDatas())) {

                        // 添加数据行
                        int number = 1;
                        for (RunningReportAlarmDetailDTO data : response.getAlarmDetailDatas()) { // 假设我们有3行数据
                            for (PageColumns column : response.getAlarmDetailColumns()) {
                                if ("number".equals(column.getDataIndex())) {
                                    // 序号
                                    PdfPCell cellContent = new PdfPCell(new Phrase(String.valueOf(number), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                    number ++;
                                } else if ("imei".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getImei(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("alarmAddress".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getAlarmAddress(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("alarmType".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getAlarmType(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("alarmTime".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getAlarmTime(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("concentration".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getConcentration(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("appealTime".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getAppealTime(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("appealStatus".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getAppealStatus(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                } else if ("valveBrokenInfo".equals(column.getDataIndex())) {
                                    PdfPCell cellContent = new PdfPCell(new Phrase(data.getValveBrokenInfo(), tableContentFont));
                                    cellContent.setHorizontalAlignment(Element.ALIGN_CENTER);
                                    cellContent.setVerticalAlignment(Element.ALIGN_MIDDLE);
                                    cellContent.setPaddingTop(paddingTop);
                                    cellContent.setPaddingBottom(paddingBottom);
                                    table.addCell(cellContent);
                                }
                            }
                        }
                    }
                    // 将表格添加到文档中
                    document.add(table);
                }
            }
            // 温馨提示
            if (response.getIsTips() == ShowAndSelectEnum.SHOW.getCode()) {
                document.setPageSize(PageSize.A4);
                document.newPage();
                // 页眉
                if (response.getHeaderShow() == ShowAndSelectEnum.SHOW.getCode()) {
                    document.add(headerTable1);
                    document.add(blankLine);
                }
                // 内容
                document.add(new Paragraph(response.getTipsContent(), contentFont));
                document.add(blankLine);
                // 温馨提示
                if (response.getTipsShow() == ShowAndSelectEnum.SHOW.getCode()) {

                    Image imgp1 = Image.getInstance(tipsPic1); // 替换为你的图片路径
                    imgp1.scaleToFit(520f, 190f); // 可选，按需求调整图片大小
                    imgp1.setAlignment(Image.MIDDLE);
                    document.add(imgp1);
                    Image imgp2 = Image.getInstance(tipsPic2); // 替换为你的图片路径
                    imgp2.scaleToFit(520f, 190f); // 可选，按需求调整图片大小
                    imgp2.setAlignment(Image.MIDDLE);
                    document.add(imgp2);
                    Image imgp3 = Image.getInstance(tipsPic3); // 替换为你的图片路径
                    imgp3.scaleToFit(520f, 190f); // 可选，按需求调整图片大小
                    imgp3.setAlignment(Image.MIDDLE);
                    document.add(imgp3);
                }
            }
        } else {
            // 无报警
            // 页眉
            if (response.getHeaderShow() == ShowAndSelectEnum.SHOW.getCode()) {
                document.add(headerTable1);
                document.add(blankLine);
            }
            // 无报警内容
            document.add(new Paragraph(response.getNoAlarmContent(), contentFont));
            document.add(blankLine);
            // 温馨提示
            if (response.getNoAlarmTipsShow() == ShowAndSelectEnum.SHOW.getCode()) {

                Image imgp1 = Image.getInstance(tipsPic1); // 替换为你的图片路径
                imgp1.scaleToFit(520f, 190f); // 可选，按需求调整图片大小
                imgp1.setAlignment(Image.MIDDLE);
                document.add(imgp1);
                Image imgp2 = Image.getInstance(tipsPic2); // 替换为你的图片路径
                imgp2.scaleToFit(520f, 190f); // 可选，按需求调整图片大小
                imgp2.setAlignment(Image.MIDDLE);
                document.add(imgp2);
                Image imgp3 = Image.getInstance(tipsPic3); // 替换为你的图片路径
                imgp3.scaleToFit(520f, 190f); // 可选，按需求调整图片大小
                imgp3.setAlignment(Image.MIDDLE);
                document.add(imgp3);
            }
        }

        // 关闭文档，确保所有内容被写入输出流
        document.close();
        // 将输出流转换为字节数组
        byte[] pdfBytes = byteArrayOutputStream.toByteArray();
        // 创建一个基于上述字节数组的ByteArrayInputStream
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(pdfBytes);
        export.setExportStatus("2");

        return byteArrayInputStream;
    }

    private static String getCMD(String txtPath, String picTmpPath, String picPath)

    {
        if (org.apache.commons.lang.StringUtils.isBlank(txtPath) || org.apache.commons.lang.StringUtils.isBlank(picTmpPath) || org.apache.commons.lang.StringUtils.isBlank(picPath))
        {
            log.info("txtPath or picTmpPath or picPath is blank");
        }

            // 未自定义截图宽度和高度，会使用默认宽、高
            return FILE_ECHART_PATH+phantomPath + " " + FILE_ECHART_PATH+JSpath + " -txtPath " + txtPath + " -picTmpPath " + picTmpPath + " -picPath "
                    + picPath + " -width 448 -height 400";
    }

    private static void init() {
        if (!initFlag) {
            File dir = new File(FILE_ECHART_PATH);
            File dir2 = new File(FILE_DATA_TXT_PATH);
            File dir3 = new File(FILE_ECHART_IMG_PATH);
            File file = new File(dir, "png1.png");

            if (!dir2.exists() || !dir2.isDirectory()) {
                dir2.mkdirs();
            }
            if (!dir3.exists() || !dir3.isDirectory()) {
                dir3.mkdirs();
            }
            if (!file.exists()) {
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                log.info("echart文件初始化，初始化目录{0}", FILE_ECHART_PATH);
                try {
                    Enumeration<URL> fontsDir = RunningReportServiceImpl.class.getClassLoader().getResources(ECHARTS);
                    while (fontsDir.hasMoreElements()) {
                        // 获取下一个元素
                        URL url = fontsDir.nextElement();
                        // 得到协议的名称
                        String protocol = url.getProtocol();
                        log.info("protocol1-urlpath:{}", url.getPath());
                        log.info("protocol1:{}", protocol);
                        if ("file".equals(protocol)) {
                            String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                            log.info("protocol1-filePath:{}", protocol);
                            copyDir(new File(filePath), dir);
                        }
                        else if ("jar".equals(protocol)) {
                            copyJar(url, dir, ECHARTS);
                        }
                    }
                }
                catch (Exception e) {
                    throw new UtilException(e);
                }
            }
            File dirFont = new File(FILE_FONT_PATH);
            File fileFont = new File(dirFont, "simsun.ttf");
            if (!fileFont.exists()) {
                if (!dirFont.exists()) {
                    dirFont.mkdirs();
                }
                log.info("字体文件初始化，初始化目录{0}", FILE_FONT_PATH);
                try {
                    Enumeration<URL> fontsDir = RunningReportServiceImpl.class.getClassLoader().getResources(FONTS);
                    while (fontsDir.hasMoreElements()) {
                        // 获取下一个元素
                        URL url = fontsDir.nextElement();
                        // 得到协议的名称
                        String protocol = url.getProtocol();
                        log.info("protocol1-urlpath:{}", url.getPath());
                        log.info("protocol1:{}", protocol);
                        if ("file".equals(protocol)) {
                            String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                            log.info("protocol1-filePath:{}", protocol);
                            copyDir(new File(filePath), dirFont);
                        }
                        else if ("jar".equals(protocol)) {
                            copyJar(url, dirFont, FONTS);
                        }
                    }
                }
                catch (Exception e) {
                    throw new UtilException(e);
                }
            }
//            if (BASEFONT == null) {
//                BaseFont bf =BaseFont.createFont("C:/WINDOWS/Fonts/simsun.ttf", BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED);
//                BaseFont simsunBaseFont = BaseFont.createFont("", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED, false, "SimSun", 0);
////                    InputStream inputStream = new ClassPathResource("fonts/simsun.ttf").getInputStream();
////                    java.awt.Font chartTitleFont = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, inputStream).deriveFont(java.awt.Font.PLAIN, 25);
////                    log.info("加载字体文件成功chartTitleFont:{}", chartTitleFont.toString());
////                    InputStream inputStream2 = new ClassPathResource("fonts/simsun.ttf").getInputStream();
////                    java.awt.Font chartContentFont = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, inputStream2).deriveFont(java.awt.Font.PLAIN, 12);
////                    log.info("加载字体文件成功chartContentFont:{}",chartContentFont.toString());
//                try {
//                    baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
//                } catch (DocumentException e) {
//                    log.info("加载字体文件失败：{}", e);
//                    throw new RuntimeException(e);
//                } catch (IOException e) {
//                    log.info("加载字体文件失败：{}", e);
//                    throw new RuntimeException(e);
//                }
//            }
            initFlag = true;
        }
    }


    private static void copyDir(final File src, final File target) {
        if (src.exists() && src.isDirectory()) {
            File[] srcfiles = src.listFiles();
            for (File f : srcfiles) {
                if (f.exists() && f.isFile()) {
                    File t = new File(target, f.getName());
                    log.info("开始拷贝文件{0}-->{1}", f.getAbsolutePath(), t.getAbsoluteFile());
                    IOUtil.copyFile(f, t);
                    log.info("拷贝文件成功{0}-->{1}", f.getAbsolutePath(), t.getAbsoluteFile());
                }
            }
        }
    }

    private static void copyJar(final URL src, final File target, final String dirName) throws IOException {
        JarFile jar = ((JarURLConnection) src.openConnection()).getJarFile();
        // 从此jar包 得到一个枚举类
        Enumeration<JarEntry> entries = jar.entries();
        ClassLoader loader = RunningReportServiceImpl.class.getClassLoader();
        String prefix = dirName + "/";
        // 同样的进行循环迭代
        while (entries.hasMoreElements()) {
            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件
            JarEntry entry = entries.nextElement();
            String name = entry.getName();
            if (!entry.isDirectory() && name.startsWith(prefix) && name.indexOf("/", prefix.length() + 1) == -1) {
                File t = new File(target, name.substring(prefix.length()));
                log.info("开始拷贝文件{}-->{}", name, t.getAbsoluteFile());
                IOUtil.copyFileFromInputStream(t.getAbsolutePath(), loader.getResourceAsStream(name));
                log.info("拷贝文件成功{}-->{}", name, t.getAbsoluteFile());
            }
        }
    }


    public static void start(String txtPath, String picTmpPath, String picPath, String width, String height) {
        // 赋予权限
        chmod();
        List<String> commandList = Arrays.asList(
                FILE_ECHART_PATH+phantomPath,
                FILE_ECHART_PATH+JSpath,
                "-txtPath",
                txtPath,
                "-picTmpPath",
                picTmpPath,
                "-picPath",
                picPath,
                "-width",
                width,
                "-height",
                height
        );

//        BufferedReader reader = null;
//        String line = null;
        ProcessBuilder pb = new ProcessBuilder(commandList);
//        pb.directory(new File(GsscConfig.SHELL_FILE_Dir));
//        int runningStatus = 0;
//        String s = null;
        try {
            Process process = pb.start();
            // 可以通过process.getInputStream()和process.getErrorStream()获取命令执行的输出和错误信息
            // 并且通过process.waitFor()等待命令执行完成并获取退出状态码

            // 读取标准输出
            BufferedReader stdOutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = stdOutReader.readLine()) != null) {
                log.info("echart-读取标准输出:{}", line);
            }

            // 读取错误输出
            BufferedReader stdErrReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            while ((line = stdErrReader.readLine()) != null) {
                log.info("echart-读取错误输出:{}", line);
            }

            // 等待命令执行结束并获取退出状态码
            int exitCode = process.waitFor();
            log.info("echart-exitCode:", exitCode);
//            System.out.println("Exit code: " + exitCode);

        } catch (IOException | InterruptedException e) {
            log.info("linux命令行生成ecahrt图失败{}", e);
            e.printStackTrace();
        }
    }

    public static void chmod() {
        List<String> commandList = Arrays.asList(
                "chmod",
                "u+x",
                FILE_ECHART_PATH+phantomPath
        );

//        BufferedReader reader = null;
//        String line = null;
        ProcessBuilder pb = new ProcessBuilder(commandList);
//        pb.directory(new File(GsscConfig.SHELL_FILE_Dir));
//        int runningStatus = 0;
//        String s = null;
        try {
            Process process = pb.start();
            // 可以通过process.getInputStream()和process.getErrorStream()获取命令执行的输出和错误信息
            // 并且通过process.waitFor()等待命令执行完成并获取退出状态码

            // 读取标准输出
            BufferedReader stdOutReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            while ((line = stdOutReader.readLine()) != null) {
                log.info("phantomjs-读取标准输出:{}", line);
            }

            // 读取错误输出
            BufferedReader stdErrReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
            while ((line = stdErrReader.readLine()) != null) {
                log.info("phantomjs-读取错误输出:{}", line);
            }

            // 等待命令执行结束并获取退出状态码
            int exitCode = process.waitFor();
            log.info("phantomjs-exitCode:", exitCode);
//            System.out.println("Exit code: " + exitCode);

        } catch (IOException | InterruptedException e) {
            log.info("linux命令行phantomjs失败{}", e);
            e.printStackTrace();
        }
    }

    static class CustomHeaderHandler extends PdfPageEventHelper {

        @Override
        public void onStartPage(PdfWriter writer, Document document) {
            log.info("触发");

        }

    }

    public static String getRandom() {
        return UUID.randomUUID().toString().replace("-","").substring(0,6);
    }


    public void pushMsg(RunningReport runningReport) {
        QueryWrapper<Dtu> query = new QueryWrapper<>();
        query.lambda().or().eq(Dtu::getIsDeleted, 0)
            .eq(Dtu::getSpId, runningReport.getSpId())
            .eq(Dtu::getConsumerId, runningReport.getConsumerId());
        List<Dtu> dtus = dtuMapper.selectList(query);
        List<ConsoleSkUserListData> consoleSkUserListData = new ArrayList<>();
        List<Integer> userId = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dtus)) {
            for (Dtu dtu : dtus) {
                if (!dtu.getIMEI().contains("-")) {
                    log.info("运行报告查询家庭成员" + dtu.getIMEI());
                    ConsoleSkUserListResponse consoleSkUserListResponse = consoleSkFeignClient
                            .alarmSOSUserList(dtu.getIMEI());
                    log.info(new StringBuilder().append("需要给运行报告").append(dtu.getIMEI()).append("的家庭成员发送信息，信息如下")
                            .append(consoleSkUserListResponse).toString());
                    //String title = Constants.RUNNING_REPORT_MESSAGE_TITLE;
                    if (consoleSkUserListResponse != null && consoleSkUserListResponse.getData() != null
                            && CollectionUtil.isNotEmpty(consoleSkUserListResponse.getData().getUserList())) {
                        if (!userId.contains(consoleSkUserListResponse.getData().getHomeId())) {
                            userId.add(consoleSkUserListResponse.getData().getHomeId());
                            consoleSkUserListData.add(consoleSkUserListResponse.getData());
                        }
                    }
                }
            }
        }
        log.info("运行报告开始发送消息的具体内容为" + consoleSkUserListData);
        String title = Constants.RUNNING_REPORT_MESSAGE_TITLE;
        String wapUrl = String.format(Constants.RUNNINGREPORT_PREVIEW, Constants.BLANK, runningReport.getReportDate(), Constants.BLANK, Constants.BLANK);
        String appUrl = String.format(Constants.RUNNINGREPORT_H5, h5CommonPath, Constants.BLANK, runningReport.getReportDate(), Constants.BLANK, Constants.BLANK);
        if (CollectionUtils.isNotEmpty(consoleSkUserListData)) {
            for (ConsoleSkUserListData consoleSkUserListDatum : consoleSkUserListData) {
                String msgs = String.format(Constants.RUNNING_REPORT_SEND_MESSAGE, consoleSkUserListDatum.getHomeName(), runningReport.getReportDate());;

                // 循环发送家庭其他成员
                for (ConsoleSkUserData consoleSkUserData : consoleSkUserListDatum.getUserList()) {
                    // 站内信参数封装
                    cn.hutool.json.JSONObject cmsReqParams = cmsMessageService.getCmsJSONParams(msgs, title,
                        consoleSkUserData.getUserId(), wapUrl, appUrl);
                    // 站内信发送

                    CmsInfoResDTO cmsInfoResDTO = cmsMessageService.sendCmsMsg(cmsReqParams);
                    log.info("运行报告APP站内信发送-request：{}，response：{}" ,cmsReqParams, cmsInfoResDTO);
                    // 小程序参数封装,小程序订阅消息
                    cn.hutool.json.JSONObject appletJSONParams = appletMessageService.getRunningReportParams(consoleSkUserListDatum.getHomeName(),
                        consoleSkUserData.getUserId(), title, runningReport.getReportDate(), wapUrl);
                    // 小程序发送
                    CmsInfoResDTO cmsInfoResDTO2 = appletMessageService.sendAppletMsg(appletJSONParams);
                    log.info("运行报告小程序站内信发送-request：{}，response：{}" ,appletJSONParams, cmsInfoResDTO2);
                }
            }
        }

    }


    /**
     * 根据客户id查询设备列表
     * @param consumerId
     * @return
     */
    @Override
    public List<RunningReportDeviceListResponse> queryDeviceListByConsumerId(Integer consumerId) {
        String spId = ApplicationUtils.getWorkingSpId();

        LambdaQueryWrapper<Dtu> dtuQueryWrapper = new LambdaQueryWrapper();
        dtuQueryWrapper.eq(Dtu::getConsumerId, consumerId)
            .eq(Dtu::getIsDeleted, IS_DELETED_FALSE)
            .eq(Dtu::getSpId, spId);
        List<Dtu> dtuList = dtuMapper.selectList(dtuQueryWrapper);
        return dtuList.stream().map(x -> {
            RunningReportDeviceListResponse vo = new RunningReportDeviceListResponse();
            vo.setImei(x.getIMEI());
            vo.setEquipmentType(x.getEquipmentType());
            vo.setEquipmentTypeName(EquipmentType.parse(x.getEquipmentType()).getName());
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public RunningReportPreviewResponse runningReportPreviewDetail(Integer id) {
        String spId = ApplicationUtils.getWorkingSpId();
        LambdaQueryWrapper<RunningReport> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RunningReport::getId, id)
            .eq(RunningReport::getIsDeleted, IS_DELETED_FALSE)
            .eq(RunningReport::getSpId, spId);
        RunningReport runningReport = runningReportMapper.selectOne(queryWrapper);
        if (ObjectUtils.isEmpty(runningReport)) {
            throw new BizException("运行报告不存在！");
        }
        RunningReportPreviewResponse response = new RunningReportPreviewResponse();
        BeanUtils.copyProperties(runningReport, response);
        response.setEquipmentTypeName(EquipmentType.parse(response.getEquipmentType()).getName());
        return response;

    }

    @Override
    public void editRunningReportPreview(RunningReportEditPreviewRequest request) {
        LogVO vo = new LogVO();
        try{
            RunningReport runningReport = this.getById(request.getId());
            if (ObjectUtils.isEmpty(runningReport)) {
                throw new BizException("运行报告不存在！");
            }
            if (runningReport.getCheckStatus() != 0) {
                throw new BizException("运行报告当前状态不支持预览！");
            }
            // 校验手机号是不是时刻家会员
            List<PhoneUserDTO> phoneUserList = userRemoteService.getUsersByPhoneList(Arrays.asList(request.getPhone()));
            log.info("editRunningReportPreview-phoneUserList：{}", JSONObject.toJSONString(phoneUserList));
            if (CollectionUtils.isEmpty(phoneUserList)) {
                throw new BizException("手机号不存在！");
            }

            runningReport.setPhone(request.getPhone());
            runningReport.setImei(request.getImei());
            runningReport.setEquipmentType(request.getEquipmentType());
            runningReport.setIsAdvanceSend(0);
            runningReportMapper.updateById(runningReport);

            vo.setDetail(new StringBuffer("手机号【").append(request.getPhone()).append("】预览成功").toString());
            log.info("LogVO-vo:{}", JSONObject.toJSONString(vo));
            // 发送C端预览链接，不受报警策略和配置控制
            pushPreviewMsg(runningReport, phoneUserList.get(0).getUserId());
            LogRecordAspect.threadLocal.set(vo);
        } catch(Exception e) {
            vo.setDetail(new StringBuffer("手机号【").append(request.getPhone()).append("】预览失败").toString());
            LogRecordAspect.threadLocal.set(vo);
            throw new BizException(e.getMessage());
        }
    }

    /**
     *
     * @param runningReport
     */
    public void pushPreviewMsg(RunningReport runningReport, Integer userId) {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.HOUR_OF_DAY, 2);
        ConsoleSkUserData sendUser = new ConsoleSkUserData();
        sendUser.setPhone(runningReport.getPhone());
        sendUser.setUserId(userId);
        sendUser.setUserRole(0);
        ConsoleSkUserListData sendData = new ConsoleSkUserListData();
        sendData.setEquName(runningReport.getImei());
        sendData.setHomeName(Constants.BLANK);

        String title = Constants.RUNNING_REPORT_PREVIEW_MESSAGE_TITLE;
        String msgs = String.format(Constants.RUNNING_REPORT_PREVIEW_SEND_MESSAGE, runningReport.getReportDate());;
        String wapUrl = String.format(Constants.RUNNINGREPORT_PREVIEW, runningReport.getImei(), runningReport.getReportDate(), 1, c.getTime().getTime());
        String appUrl = String.format(Constants.RUNNINGREPORT_H5, h5CommonPath, runningReport.getImei(), runningReport.getReportDate(), 1, c.getTime().getTime());

        // 站内信参数封装
        cn.hutool.json.JSONObject cmsReqParams = cmsMessageService.getCmsJSONParams(msgs, title,
                sendUser.getUserId(), wapUrl, appUrl);
        // 站内信发送
        CmsInfoResDTO appResult = cmsMessageService.sendCmsMsg(cmsReqParams);
        log.info("C端预览运行报告APP站内信发送-request：{}，response：{}" ,cmsReqParams, appResult);

//        // 小程序参数封装
//        cn.hutool.json.JSONObject appletJSONParams = appletMessageService.getRunningReportParams(sendData.getHomeName(),
//                sendUser.getUserId(), title, runningReport.getReportDate(), page);
//        // 小程序发送
//        CmsInfoResDTO appletResult = appletMessageService.sendAppletMsg(appletJSONParams);
//        log.info("C端预览运行报告小程序站内信发送-request：{}，response：{}" ,appletJSONParams, appletResult);


    }


    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param
     * @return
     */
    public List<RunningReportOnOffDTO> getOnOffDataList(InfluxDBConnect influxDBConnect, Dtu dtu, String startTime, String nextTime) {
        List<RunningReportOnOffDTO> resultList = new ArrayList<>();
        // 查询本月开关机记录
        String selectSql = new StringBuffer("select * from PowerLogAsDtu where Path='").append(dtu.getPath())
            .append("' AND DtuId = '").append(dtu.getIMEI()).append("' AND ConsumerId = ").append(dtu.getConsumerId())
            .append(" AND time > '").append(startTime).append("' AND time < '").append(nextTime)
            .append("' order by time asc").toString();
        log.info("getOnOffDataList-selectSql:{}", selectSql);
        QueryResult thisMonthResult = influxDBConnect.query(selectSql);
        List<List<Object>> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        if (thisMonthResult.getResults().get(0).getSeries() != null) {
            columns = thisMonthResult.getResults().get(0).getSeries().get(0).getColumns();
            list = thisMonthResult.getResults().get(0).getSeries().get(0).getValues();
        }
        log.info("runningReportJob-getOnOffDataList:{}", list.toString());
        for (List<Object> objects : list) {
            //log.info("objects1：{}", objects.get(9));
            RunningReportOnOffDTO res = new RunningReportOnOffDTO();
            res.setOffline(Boolean.valueOf(objects.get(columns.indexOf("Offline")).toString()));
            res.setOfflineType(0);
            if (res.isOffline() && objects.get(columns.indexOf("Version")).toString().equals("1000")) {
                res.setOfflineType(1); // 周期性离线
            }
            res.setTime(DateUtil.parse(objects.get(columns.indexOf("time")).toString()));
            res.setSecond(res.getTime().getTime() / 1000);

            resultList.add(res);
        }
        return resultList;
    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param
     * @return
     */
    public RunningReportOnOffDTO getLastOnOffData(InfluxDBConnect influxDBConnect, Dtu dtu, String startTime) {
        // 查询本月的上一条开关机记录
        String selectSql = new StringBuffer("select * from PowerLogAsDtu where Path='").append(dtu.getPath())
            .append("' AND DtuId = '").append(dtu.getIMEI()).append("' AND ConsumerId = ").append(dtu.getConsumerId())
            .append(" AND time < '").append(startTime)
            .append("' order by time desc limit 1 offset 0").toString();
        log.info("getLastOnOffData-selectSql:{}", selectSql);
        QueryResult thisMonthResult = influxDBConnect.query(selectSql);
        List<List<Object>> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        if (thisMonthResult.getResults().get(0).getSeries() != null) {
            columns = thisMonthResult.getResults().get(0).getSeries().get(0).getColumns();
            list = thisMonthResult.getResults().get(0).getSeries().get(0).getValues();
        }
        log.info("runningReportJob-getLastOnOffData:{}", list.toString());
        for (List<Object> objects : list) {
            RunningReportOnOffDTO res = new RunningReportOnOffDTO();
            res.setOffline(Boolean.valueOf(objects.get(columns.indexOf("Offline")).toString()));
            res.setOfflineType(0);
            if (res.isOffline() && objects.get(columns.indexOf("Version")).toString().equals("1000")) {
                res.setOfflineType(1); // 周期性离线
            }
            res.setTime(DateUtil.parse(objects.get(columns.indexOf("time")).toString()));
            res.setSecond(res.getTime().getTime() / 1000);

            return res;
        }
        return null;
    }

    /**
     * 根据无需审核配置获取所有无需审核的组合
     * @param
     * @return
     */
    public RunningReportOnOffDTO getNextOnOffData(InfluxDBConnect influxDBConnect, Dtu dtu, String nextTime) {
        // 查询本月的下一条开关机记录
        String selectSql = new StringBuffer("select * from PowerLogAsDtu where Path='").append(dtu.getPath())
            .append("' AND DtuId = '").append(dtu.getIMEI()).append("' AND ConsumerId = ").append(dtu.getConsumerId())
            .append(" AND time > '").append(nextTime)
            .append("' order by time asc limit 1 offset 0").toString();
        log.info("getNextOnOffData-selectSql:{}", selectSql);
        QueryResult thisMonthResult = influxDBConnect.query(selectSql);
        List<List<Object>> list = new ArrayList<>();
        List<String> columns = new ArrayList<>();
        if (thisMonthResult.getResults().get(0).getSeries() != null) {
            columns = thisMonthResult.getResults().get(0).getSeries().get(0).getColumns();
            list = thisMonthResult.getResults().get(0).getSeries().get(0).getValues();
        }
        log.info("runningReportJob-getNextOnOffData:{}", list.toString());
        for (List<Object> objects : list) {
            RunningReportOnOffDTO res = new RunningReportOnOffDTO();
            res.setOffline(Boolean.valueOf(objects.get(columns.indexOf("Offline")).toString()));
            res.setOfflineType(0);
            if (res.isOffline() && objects.get(columns.indexOf("Version")).toString().equals("1000")) {
                res.setOfflineType(1); // 周期性离线
            }
            res.setTime(DateUtil.parse(objects.get(columns.indexOf("time")).toString()));
            res.setSecond(res.getTime().getTime() / 1000);

            return res;
        }
        return null;
    }

    /**
     * 组装列表
     * @param list 列表数据
     * @param lastData 上一条数据
     * @param nextData 下一条数据
     * @return
     */
    public void assembleOnOffDataList(List<RunningReportOnOffDTO> list, RunningReportOnOffDTO lastData, RunningReportOnOffDTO nextData) {
        if (lastData != null) {
            list.add(0, lastData);
        }
        if (nextData != null) {
            list.add(nextData);
        }
    }

}
